<commit_before><?php
/**
 * DinklyBase
 *
 * Children of this class should contain only static functions that return arrays
 *
 * @package    Dinkly
 * @subpackage CoreClasses
 * @author     <NAME> <<EMAIL>>
 */

use Symfony\Component\Yaml\Yaml;

class DinklyBase
{
	protected $module_header;

	protected $context;

	protected $view;

	protected $module;

	protected $parameters;

	//***************************************************************************** NONSTATIC FUNCTIONS

	/**
	 * Initialize dinkly session, Get app root and reset session root if not matching
	 *
	 * @param bool $enable_cache default true or enter false to flush session cache
	 * 
	 * 
	 */
	public function __construct($enable_cache = true)
	{
		//If the dinkly session doesn't exist yet, create it
		if(!isset($_SESSION['dinkly']) || !$enable_cache) $_SESSION['dinkly'] = array();

		//If the dinkly setting for the app root doesn't exist, create it
		if(!isset($_SESSION['dinkly']['app_root'])) { $_SESSION['dinkly']['app_root'] = $_SERVER['APPLICATION_ROOT']; }

		//If the current application root does not match what we have in session, reset the dinkly session
		//...this prevents issues when going from one Dinkly project to another in a local environment
		if($_SERVER['APPLICATION_ROOT'] != $_SESSION['dinkly']['app_root']) { $_SESSION['dinkly'] = array(); }
	}
	/**
	 * Interpret friendly URLS and load app and module based on Context 
	 * as well as interpreting parameters where applicable
	 * @param string $uri default null to be parsed to get correct context
	 * @return Array of matching objects or false if not found
	 */
	public function route($uri = null)
	{
		$parameters = array();

		if(stristr($uri, '?'))
		{
			$orig = $uri;
			$pos = strpos($uri, '?');
			$uri = substr($uri, 0, $pos);
			$query_string = substr($orig, $pos + 1);
			parse_str($query_string, $parameters);
		}

		$module = $view = null;

		$context = $this->getContext($uri);
		$context['parameters'] = array_merge($context['parameters'], $parameters);

		$_SESSION['dinkly']['current_app_name'] = $context['current_app_name'];

		$this->loadApp($context['current_app_name']);

		$this->loadModule($context['current_app_name'], $context['module'], $context['view'], false, true, $context['parameters']);
	}
	/**
	 * Fetch the current context of the application based on URL
	 * 
	 * @param string $uri default null to be parsed to get correct context
	 * @return Array $context containing current app, module and view
	 */
	public function getContext($uri = null)
	{
		if(!$this->context)
		{
			if(!$uri) { $uri = $_SERVER['REQUEST_URI']; }

			$current_app_name = $module = $view = null;
			$context = $parameters = array();

			$default_app_name = self::getDefaultApp(true);
			$config = self::getConfig();

			$uri_parts = array_filter(explode("/", $uri));

			//If the URL is empty, give it a slash so it can match in the config
			if($uri_parts == array()) { $uri_parts = array(1 => '/'); }

			//Figure out the current app, assume the default if we don't get one in the URL
			foreach($config as $app => $values)
			{
				if($app != 'global')
				{
					if(!isset($values['base_href']))
					{
						throw new Exception('base_href key/value pair missing from config.yml');
					}
					$base_href = str_replace('/', '', $values['base_href']);
					
					if(strlen($base_href) == 0) { $base_href = '/'; }
					
					if($uri_parts[1] == $base_href)
					{
						$context['current_app_name'] = $app;

						//kick the app off the uri and reindex
						array_shift($uri_parts); 

						break;
					}
				}
			}

			//No match, set default app
			if(!isset($context['current_app_name'])) { $context['current_app_name'] = $default_app_name; }

			//Reset indexes if needed
			$uri_parts = array_values($uri_parts);

			//Figure out the module and view
			if(sizeof($uri_parts) == 1) { $context['module'] = $uri_parts[0]; $context['view'] = 'default'; }
			else if(sizeof($uri_parts) == 2) { $context['module'] = $uri_parts[0]; $context['view'] = $uri_parts[1]; }
			else if(sizeof($uri_parts) > 2)
			{
				for($i = 0; $i < sizeof($uri_parts); $i++)
				{
					if($i == 0) { $context['module'] = $uri_parts[0]; }
					else if($i == 1) { $context['view'] = $uri_parts[1]; }
					else
					{
						if(isset($uri_parts[$i+1]))
						{
							$parameters[$uri_parts[$i]] = $uri_parts[$i+1];
							$i++;
						}
						else
						{
							$parameters[$uri_parts[$i]] = true;
						}
					}
				}    
			}

			if(!isset($context['module'])) { $context['module'] = Dinkly::getConfigValue('default_module', $context['current_app_name']); }
			if(!isset($context['view'])) { $context['view'] = 'default'; }

			$context['parameters'] = $parameters;

			$this->context = $context;
		}

		return $this->context;
	}
	/**
	 * Load error Page when given a app that doesn't exist in context or 
	 * load default module if no error file
	 *
	 * @param string $app_name name of app we are trying to load
	 * @param string $camel_module_name module we are looking for in camel case
	 * 
	 * 
	 */
	public function loadError($app_name, $camel_module_name)
	{
		$error_controller = $_SERVER['APPLICATION_ROOT'] . "/apps/" . $app_name . "/modules/error/ErrorController.php";
			
		if(file_exists($error_controller))
		{
			$camel_module_name = "ErrorController";
			$module_name = 'error';
			$controller_file = $error_controller;
			$view_name = '404';
		}
		else
		{
			//Check for base dinkly 404
			$error_controller = $_SERVER['APPLICATION_ROOT'] . "/apps/error/modules/error/ErrorController.php";
			
			if(file_exists($error_controller))
			{
				$app_name = 'error';
				$camel_module_name = "ErrorController";
				$module_name = 'error';
				$controller_file = $error_controller;
				$view_name = '404';
			}
			else
			{
				$camel_module_name = self::convertToCamelCase(self::getConfigValue('default_module', $app_name), true) . "Controller";
				$module_name = self::getConfigValue('default_module', $app_name);
				$controller_file = $_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . self::getConfigValue('default_module', $app_name) . '/' . $camel_module_name . ".php";
			}
		}
	}

	public function loadApp($app_name)
	{
		$camel_app_controller_name = self::convertToCamelCase($app_name, true) . "Controller";
		$app_controller_file = $_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/' . $camel_app_controller_name . '.php';

		if(!file_exists($app_controller_file))
		{
			$this->loadError($app_name, 'DefaultController');
			return false;
		}

		//Instantiate controller object
		require_once $app_controller_file;
		$controller = new $camel_app_controller_name();

		return true;
	}

	//Dinkly's most badass function. Loads a desired module, and redirects if you ask it nicely.
	public function loadModule($app_name, $module_name = null, $view_name = 'default', $redirect = false, $draw_layout = true, $parameters = null)
	{
		//If the app_name is not passed, assume whichever is set as the default in config.yml
		if(!$app_name) $app_name = Dinkly::getDefaultApp(true);
		
		//Set the current app to match whatever was passed
		$_SESSION['dinkly']['current_app_name'] = $app_name;

		//If no view is passed, look for one called 'default'
		if(!$view_name) $view_name = 'default';

		//Determine if we are currently on this module/view or not
		if($redirect)
		{
			$base_href = Dinkly::getConfigValue('base_href', $app_name);
			if($base_href == '/') { $base_href = null; }
			$path = $base_href . '/' . $module_name . '/' . $view_name;

			//Deal with parameters
			if($parameters)
			{
				foreach($parameters as $key => $value)
				{
					$path .= '/' . $key . '/' . $value;
				}
			}

			header("Location: " . $path);
		}

		//Get module controller
		$camel_module_name = self::convertToCamelCase($module_name, true) . "Controller";
		$controller_file = $_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . '/' . $camel_module_name . '.php';

		//Save these on the object so they can be retrieved as needed in controllers or views
		$this->view = $view_name;
		$this->module = $module_name;
		$this->parameters = $parameters;

		//If the controller doesn't exist, load 404 error page if one is available, otherwise load default module
		if(!file_exists($controller_file))
		{
			$this->loadError($app_name, $camel_module_name);

			return false;
		}

		//Instantiate controller object
		require_once $controller_file;
		$controller = new $camel_module_name();

		//Migrate current dinkly variables over to our new controller
		$vars = get_object_vars($this);
		foreach ($vars as $name => $value) { $controller->$name = $value; }

		//Get this view's function
		$view_controller_name = self::convertToCamelCase($view_name, true);
		$view_function = "load" . $view_controller_name;

		if(method_exists($controller, $view_function))
		{
			if($controller->$view_function($parameters))
			{
				if(!in_array($module_name, Dinkly::getValidModules($app_name)))
				{
					return false;
				}

				//Migrate the scope of the declared variables to be local to the view
				$vars = get_object_vars($controller);
				foreach ($vars as $name => $value)
					$$name = $value;

				//Get module view
				if(file_exists($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . '/views/' . $view_name . ".php"))
				{
					if($draw_layout)
					{
						if(file_exists($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . "/views/header.php"))
						{
							ob_start();
							include($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . "/views/header.php");
							$header = ob_get_contents();
							ob_end_clean();
							$this->setModuleHeader($header);
						}
						
						//Set the powered-by header if the version number is in the config
						if($version = self::getConfigValue('dinkly_version', 'global'))
						{
							header('X-Powered-By: DINKLY/' . $version);
						}

						include($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/layout/header.php');
					}

					require_once($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . '/views/' . $view_name . ".php");
					
					if($draw_layout)
					{
						require_once($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/layout/footer.php');
					}
				}
			}
		}

		return true;
	}

	//Set the module header.
	public function setModuleHeader($header) { $this->module_header = $header; }

	//Returns the contents of the module header.
	public function getModuleHeader() { return $this->module_header; }

	//Return the current context's view
	public function getCurrentView()
	{
		if(!$this->view)
		{
			$context = $this->getContext();
			$this->view = $context['view'];
		}
		return $this->view;
	}

	//Return the current context's module
	public function getCurrentModule()
	{
		if(!$this->module)
		{
			$context = $this->getContext();
			$this->module = $context['module'];
		}
		return $this->module;
	}

	//Return parameters
	public function getParameters()
	{
		if(!$this->parameters)
		{
			$context = $this->getContext();<commit_msg>working on DinklyBase php doc<commit_after><?php
/**
 * DinklyBase
 *
 * Children of this class should contain only static functions that return arrays
 *
 * @package    Dinkly
 * @subpackage CoreClasses
 * @author     <NAME> <<EMAIL>>
 */

use Symfony\Component\Yaml\Yaml;

class DinklyBase
{
	protected $module_header;

	protected $context;

	protected $view;

	protected $module;

	protected $parameters;

	//***************************************************************************** NONSTATIC FUNCTIONS

	/**
	 * Initialize dinkly session, Get app root and reset session root if not matching
	 *
	 * @param bool $enable_cache default true or enter false to flush session cache
	 * 
	 * 
	 */
	public function __construct($enable_cache = true)
	{
		//If the dinkly session doesn't exist yet, create it
		if(!isset($_SESSION['dinkly']) || !$enable_cache) $_SESSION['dinkly'] = array();

		//If the dinkly setting for the app root doesn't exist, create it
		if(!isset($_SESSION['dinkly']['app_root'])) { $_SESSION['dinkly']['app_root'] = $_SERVER['APPLICATION_ROOT']; }

		//If the current application root does not match what we have in session, reset the dinkly session
		//...this prevents issues when going from one Dinkly project to another in a local environment
		if($_SERVER['APPLICATION_ROOT'] != $_SESSION['dinkly']['app_root']) { $_SESSION['dinkly'] = array(); }
	}
	/**
	 * Interpret friendly URLS and load app and module based on Context 
	 * as well as interpreting parameters where applicable
	 * @param string $uri default null to be parsed to get correct context
	 * @return Array of matching objects or false if not found
	 */
	public function route($uri = null)
	{
		$parameters = array();

		if(stristr($uri, '?'))
		{
			$orig = $uri;
			$pos = strpos($uri, '?');
			$uri = substr($uri, 0, $pos);
			$query_string = substr($orig, $pos + 1);
			parse_str($query_string, $parameters);
		}

		$module = $view = null;

		$context = $this->getContext($uri);
		$context['parameters'] = array_merge($context['parameters'], $parameters);

		$_SESSION['dinkly']['current_app_name'] = $context['current_app_name'];

		$this->loadApp($context['current_app_name']);

		$this->loadModule($context['current_app_name'], $context['module'], $context['view'], false, true, $context['parameters']);
	}
	/**
	 * Fetch the current context of the application based on URL
	 * 
	 * @param string $uri default null to be parsed to get correct context
	 * @return Array $context containing current app, module and view
	 */
	public function getContext($uri = null)
	{
		if(!$this->context)
		{
			if(!$uri) { $uri = $_SERVER['REQUEST_URI']; }

			$current_app_name = $module = $view = null;
			$context = $parameters = array();

			$default_app_name = self::getDefaultApp(true);
			$config = self::getConfig();

			$uri_parts = array_filter(explode("/", $uri));

			//If the URL is empty, give it a slash so it can match in the config
			if($uri_parts == array()) { $uri_parts = array(1 => '/'); }

			//Figure out the current app, assume the default if we don't get one in the URL
			foreach($config as $app => $values)
			{
				if($app != 'global')
				{
					if(!isset($values['base_href']))
					{
						throw new Exception('base_href key/value pair missing from config.yml');
					}
					$base_href = str_replace('/', '', $values['base_href']);
					
					if(strlen($base_href) == 0) { $base_href = '/'; }
					
					if($uri_parts[1] == $base_href)
					{
						$context['current_app_name'] = $app;

						//kick the app off the uri and reindex
						array_shift($uri_parts); 

						break;
					}
				}
			}

			//No match, set default app
			if(!isset($context['current_app_name'])) { $context['current_app_name'] = $default_app_name; }

			//Reset indexes if needed
			$uri_parts = array_values($uri_parts);

			//Figure out the module and view
			if(sizeof($uri_parts) == 1) { $context['module'] = $uri_parts[0]; $context['view'] = 'default'; }
			else if(sizeof($uri_parts) == 2) { $context['module'] = $uri_parts[0]; $context['view'] = $uri_parts[1]; }
			else if(sizeof($uri_parts) > 2)
			{
				for($i = 0; $i < sizeof($uri_parts); $i++)
				{
					if($i == 0) { $context['module'] = $uri_parts[0]; }
					else if($i == 1) { $context['view'] = $uri_parts[1]; }
					else
					{
						if(isset($uri_parts[$i+1]))
						{
							$parameters[$uri_parts[$i]] = $uri_parts[$i+1];
							$i++;
						}
						else
						{
							$parameters[$uri_parts[$i]] = true;
						}
					}
				}    
			}

			if(!isset($context['module'])) { $context['module'] = Dinkly::getConfigValue('default_module', $context['current_app_name']); }
			if(!isset($context['view'])) { $context['view'] = 'default'; }

			$context['parameters'] = $parameters;

			$this->context = $context;
		}

		return $this->context;
	}
	/**
	 * Load error Page when given a app that doesn't exist in context or 
	 * load default module if no error file
	 *
	 * @param string $app_name name of app we are trying to load
	 * @param string $camel_module_name module we are looking for in camel case
	 * 
	 * 
	 */
	public function loadError($app_name, $camel_module_name)
	{
		$error_controller = $_SERVER['APPLICATION_ROOT'] . "/apps/" . $app_name . "/modules/error/ErrorController.php";
			
		if(file_exists($error_controller))
		{
			$camel_module_name = "ErrorController";
			$module_name = 'error';
			$controller_file = $error_controller;
			$view_name = '404';
		}
		else
		{
			//Check for base dinkly 404
			$error_controller = $_SERVER['APPLICATION_ROOT'] . "/apps/error/modules/error/ErrorController.php";
			
			if(file_exists($error_controller))
			{
				$app_name = 'error';
				$camel_module_name = "ErrorController";
				$module_name = 'error';
				$controller_file = $error_controller;
				$view_name = '404';
			}
			else
			{
				$camel_module_name = self::convertToCamelCase(self::getConfigValue('default_module', $app_name), true) . "Controller";
				$module_name = self::getConfigValue('default_module', $app_name);
				$controller_file = $_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . self::getConfigValue('default_module', $app_name) . '/' . $camel_module_name . ".php";
			}
		}
	}
	/**
	 * Load application base in order to istantiate the app controller
	 * 
	 *
	 * @param string $app_name name of app we are trying to load
	 * 
	 * 
	 * @return bool true if app loaded currectly else false and sent to default app
	 */
	public function loadApp($app_name)
	{
		$camel_app_controller_name = self::convertToCamelCase($app_name, true) . "Controller";
		$app_controller_file = $_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/' . $camel_app_controller_name . '.php';

		if(!file_exists($app_controller_file))
		{
			$this->loadError($app_name, 'DefaultController');
			return false;
		}

		//Instantiate controller object
		require_once $app_controller_file;
		$controller = new $camel_app_controller_name();

		return true;
	}
	/**
	 * Load desired module and redirect if necessary
	 * 
	 *
	 * @param string $app_name name of app we are trying to load
	 * @param string $module_name string of desired module to load
	 * @param string $view string if passed goes to specified view otherwise default
	 * @param bool $redirect default false, make true to redirect to different view
	 * @param bool $draw_layout default true to get module view
	 * @param array $parameters Array of parameters that can be used to populate views
	 *
	 * @return bool true if app loaded currectly else false and sent to default app
	 */
	//Dinkly's most badass function. Loads a desired module, and redirects if you ask it nicely.
	public function loadModule($app_name, $module_name = null, $view_name = 'default', $redirect = false, $draw_layout = true, $parameters = null)
	{
		//If the app_name is not passed, assume whichever is set as the default in config.yml
		if(!$app_name) $app_name = Dinkly::getDefaultApp(true);
		
		//Set the current app to match whatever was passed
		$_SESSION['dinkly']['current_app_name'] = $app_name;

		//If no view is passed, look for one called 'default'
		if(!$view_name) $view_name = 'default';

		//Determine if we are currently on this module/view or not
		if($redirect)
		{
			$base_href = Dinkly::getConfigValue('base_href', $app_name);
			if($base_href == '/') { $base_href = null; }
			$path = $base_href . '/' . $module_name . '/' . $view_name;

			//Deal with parameters
			if($parameters)
			{
				foreach($parameters as $key => $value)
				{
					$path .= '/' . $key . '/' . $value;
				}
			}

			header("Location: " . $path);
		}

		//Get module controller
		$camel_module_name = self::convertToCamelCase($module_name, true) . "Controller";
		$controller_file = $_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . '/' . $camel_module_name . '.php';

		//Save these on the object so they can be retrieved as needed in controllers or views
		$this->view = $view_name;
		$this->module = $module_name;
		$this->parameters = $parameters;

		//If the controller doesn't exist, load 404 error page if one is available, otherwise load default module
		if(!file_exists($controller_file))
		{
			$this->loadError($app_name, $camel_module_name);

			return false;
		}

		//Instantiate controller object
		require_once $controller_file;
		$controller = new $camel_module_name();

		//Migrate current dinkly variables over to our new controller
		$vars = get_object_vars($this);
		foreach ($vars as $name => $value) { $controller->$name = $value; }

		//Get this view's function
		$view_controller_name = self::convertToCamelCase($view_name, true);
		$view_function = "load" . $view_controller_name;

		if(method_exists($controller, $view_function))
		{
			if($controller->$view_function($parameters))
			{
				if(!in_array($module_name, Dinkly::getValidModules($app_name)))
				{
					return false;
				}

				//Migrate the scope of the declared variables to be local to the view
				$vars = get_object_vars($controller);
				foreach ($vars as $name => $value)
					$$name = $value;

				//Get module view
				if(file_exists($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . '/views/' . $view_name . ".php"))
				{
					if($draw_layout)
					{
						if(file_exists($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . "/views/header.php"))
						{
							ob_start();
							include($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . "/views/header.php");
							$header = ob_get_contents();
							ob_end_clean();
							$this->setModuleHeader($header);
						}
						
						//Set the powered-by header if the version number is in the config
						if($version = self::getConfigValue('dinkly_version', 'global'))
						{
							header('X-Powered-By: DINKLY/' . $version);
						}

						include($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/layout/header.php');
					}

					require_once($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/modules/' . $module_name . '/views/' . $view_name . ".php");
					
					if($draw_layout)
					{
						require_once($_SERVER['APPLICATION_ROOT'] . '/apps/' . $app_name . '/layout/footer.php');
					}
				}
			}
		}

		return true;
	}
	/**
	 * Set module header manually
	 *
	 * @param header $header String containing contents of header.php file
	 * 
	 */
	public function setModuleHeader($header) { $this->module_header = $header; }

	/**
	 * Get contents of module header
	 *
	 * 
	 * @return header contents of header.php file of a given module
	 */
	public function getModuleHeader() { return $this->module_header; }
	/**
	 * Get current contexts view
	 *
	 * 
	 * @return view of current context
	 */
	public function getCurrentView()
	{
		if(!$this->view)
		{
			$context = $this->getContext();
			$this->view = $context['view'];
		}
		return $this->view;
	}
	/**
	 * Get current contexts module
	 *
	 * 
	 * @return module of current context
	 */
	public function getCurrentModule()
	{
		if(!$this->module)
		{
			$context = $this->getContext();
			$this->module = $context['module'];
		}
		return $this->module;
	}
	/**
	 * Get current contexts parameters
	 *
	 * 
	 * @return parameters of current context
	 */
	public function getParameters()
	{
		if(!$this->parameters)
		{
			$context = $this->getContext();
{'fraction_non_alphanumeric': 0.1595844332794005, 'fraction_numerical': 0.002554713446308439, 'mean_word_length': 3.5028757668711656, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5972657', 'n_tokens_mistral': 8816, 'n_tokens_neox': 7364, 'n_words': 1921}