PageRenderTime 55ms CodeModel.GetById 18ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/library/Sodapop/Application.php

https://github.com/18thstreetmike/sodapop_for_codaserver
PHP | 403 lines | 327 code | 47 blank | 29 comment | 84 complexity | 8f52b13de421787d008e8af524ffa725 MD5 | raw file
  1<?php
  2/**
  3 * Description of Application
  4 *
  5 * @author marace
  6 */
  7
  8class Sodapop_Application {
  9	public $config = null;
 10
 11	public $routes = null;
 12
 13	public $user = null;
 14
 15	public $title = null;
 16
 17	public $description = null;
 18
 19	public $navigation = null;
 20
 21	public $availableModels = null;
 22
 23	public $models = null;
 24
 25	public $environment = null;
 26
 27	protected $view = null;
 28
 29	public function __construct($environment, $config) {
 30		$this->environment = $environment;
 31
 32		$this->config = Sodapop_Application::parseIniFile($environment, $config, str_replace('/public/index.php', '', $_SERVER['SCRIPT_FILENAME']));
 33
 34
 35		// load the routes
 36		$routesFilePath = '../configuration/routes.yaml';
 37		if (array_key_exists('routes.file_path', $this->config)) {
 38			$routesFilePath = $this->config['routes.file_path'];
 39		}
 40		if(file_exists($routesFilePath)) {
 41			$tempRoutes = Sodapop_Yaml::loadFile($routesFilePath);
 42			if ($tempRoutes) {
 43				$this->routes = $this->processRoutesFile($tempRoutes['routes']);
 44			}
 45		}
 46
 47		// load the sitemap
 48		$sitemapFilePath = '../configuration/sitemap.yaml';
 49		if (array_key_exists('sitemap.file_path', $this->config)) {
 50			$sitemapFilePath = $this->config['sitemap.file_path'];
 51		}
 52		if(file_exists($sitemapFilePath)) {
 53			$tempSitemap = Sodapop_Yaml::loadFile($sitemapFilePath);
 54			if ($tempSitemap) {
 55				$this->title = $tempSitemap['title'];
 56				$this->description = $tempSitemap['description'];
 57				$this->navigation = $tempSitemap['navigation'];
 58				$this->availableModels = $tempSitemap['available_models'];
 59			}
 60		}
 61
 62		// load the models
 63		$modelsFilePath = '../configuration/models.yaml';
 64		if (array_key_exists('models.file_path', $this->config)) {
 65			$modelsFilePath = $this->config['models.file_path'];
 66		}
 67		if(file_exists($modelsFilePath)) {
 68			$tempModels = Sodapop_Yaml::loadFile($modelsFilePath);
 69			if ($tempModels) {
 70				$this->models = $tempModels;
 71			}
 72		}
 73
 74		// instantiate the View
 75		$viewClass = 'Sodapop_View_Toasty';
 76		if (array_key_exists('view.renderer', $this->config)) {
 77			$viewClass = $this->config['view.renderer'];
 78		}
 79		// grab the view configuration from the config variable.
 80		$viewConfig = array();
 81		foreach ($this->config as $configKey => $configValue) {
 82			if (strpos($configKey, 'view.config.') !== false) {
 83				$viewConfig[substr($configKey, 12)] = $configValue;
 84			}
 85		}
 86
 87		$this->view = new $viewClass($viewConfig, $this);
 88		$this->view->init();
 89
 90		// initialize the user
 91		$databaseClass = 'Sodapop_Database_Codaserver';
 92		if (array_key_exists('model.database.driver', $this->config)) {
 93			$databaseClass = $this->config['model.database.driver'];
 94		}
 95		if (isset($_SESSION['user'])) {
 96			$this->user = $_SESSION['user'];
 97		} else {
 98			$_SESSION['user'] = call_user_func(array($databaseClass, 'getUser'), $this->config['model.database.hostname'], $this->config['model.database.port'], $this->config['model.database.public_user'], $this->config['model.database.public_password'], $this->config['model.database.schema'], $environment, null, $this->availableModels);
 99			$this->user = $_SESSION['user'];
100		}
101
102	}
103
104	public function getNavigationItem($name) {
105		foreach ($this->navigation as $navigationItem) {
106			if ($navigationItem['id'] == $name) {
107				return $navigationItem;
108			}
109		}
110		return null;
111	}
112
113	public function bootstrap () {
114		require_once($this->config['bootstrap.file_path']);
115		$bootstrap = new Bootstrap(&$this);
116		if (method_exists($bootstrap, '_initAutoload')) {
117			$bootstrap->_initAutoload();
118		}
119		if (method_exists($bootstrap, '_initRoutes')) {
120			$bootstrap->_initRoutes();
121		}
122		if (method_exists($bootstrap, '_initSitemap')) {
123			$bootstrap->_initSitemap();
124		}
125		if (method_exists($bootstrap, '_initModel')) {
126			$bootstrap->_initModel();
127		}
128		if (method_exists($bootstrap, '_initView')) {
129			$bootstrap->_initView();
130		}
131		if (method_exists($bootstrap, '_initUser')) {
132			$bootstrap->_initUser();
133		}
134		return $this;
135	}
136
137	public function run() {
138		$controller = null;
139		$action = null;
140		$requestVariables = array();
141		$requestVariablesNumeric = array();
142
143		$requestUri = $_SERVER['REQUEST_URI'];
144		if (stripos($_SERVER['REQUEST_URI'], '?')) {
145			$requestUri = substr($_SERVER['REQUEST_URI'], 0 , stripos($_SERVER['REQUEST_URI'], '?'));
146		}
147
148		// figure out the root path
149		$indexPath = str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']);
150		$routePath = str_replace($indexPath.'/', '', $requestUri);
151
152		// see if it's in the routes
153		foreach ($this->routes as $key => $route) {
154			if (preg_match($key, $routePath) > 0) {
155				// figure out all of the variables
156				$matches = null;
157				preg_match($key, $routePath, $matches);
158				foreach ($matches as $handle => $value) {
159					if (!is_numeric($handle)) {
160						$requestVariables[$handle] = $value;
161					}
162				}
163
164				if (isset($route['url'])) {
165					$url = $route['url'];
166					$url = str_replace('APPLICATION_ROOT',  str_replace('/public/index.php', '', $_SERVER['SCRIPT_FILENAME']), $url);
167					foreach ($requestVariables as $variableName => $variableValue) {
168						$url = str_replace(':'.$variableName, $variableValue, $url);
169					}
170					header('Location: '.$url);
171					exit;
172				} else {
173					if (isset($route['controller'])) {
174						$controller = $route['controller'];
175					}
176					if (isset($route['action'])) {
177						$action = $route['action'];
178					}
179					if (isset($requestVariables['controller'])) {
180						$controller = $requestVariables['controller'];
181					}
182					if (isset($requestVariables['action'])) {
183						$action = $requestVariables['action'];
184					}
185					if ($controller == null) {
186						$controller = 'index';
187					}
188					if ($action == null) {
189						$action = 'index';
190					}
191
192					$request = new Sodapop_Request();
193					$request->setRequestVariables($requestVariables);
194
195					$this->loadControllerAction($controller, $action, $request, $this->view, $indexPath);
196				}
197
198
199			}
200
201		}
202
203		// resolve the controller and action, set up the request.
204		$routePathParts = explode('/', $routePath);
205		if (count($routePathParts) == 0 || trim($routePathParts[0]) == '') {
206			$controller = 'index';
207			$action = 'index';
208		} else if (count($routePathParts) == 1) {
209			$controller = $routePathParts[0];
210			$action = 'index';
211		} else if (count($routePathParts) == 2) {
212			$controller = $routePathParts[0];
213			$action = $routePathParts[1];
214		} else {
215			$controller = $routePathParts[0];
216			$action = $routePathParts[1];
217			for ($i = 2; $i < count($routePathParts); $i++) {
218				$requestVariablesNumeric[$i - 2] = $routePathParts[$i];
219				if ($i % 2 == 0 && isset($routePathParts[$i + 1])) {
220					$requestVariables[$routePathParts[$i]] = $routePathParts[$i + 1];
221				}
222			}
223		}
224		foreach($_REQUEST as $name => $value) {
225			$requestVariables[$name] = $value;
226		}
227
228
229		$request = new Sodapop_Request();
230		$request->setRequestVariables($requestVariables);
231		$request->setRequestVariablesNumeric($requestVariablesNumeric);
232
233		$this->loadControllerAction($controller, $action, $request, $this->view, $indexPath);
234
235	}
236
237	public function loadControllerAction($controller, $action, $request, $view, $baseUrl) {
238		try {
239			$actionMethod = $action.'Action';
240			@include_once($this->config['controller.directory'].'/'.ucfirst($controller).'Controller.php');
241			$controllerName = ucfirst($controller).'Controller';
242			$controllerObj = new $controllerName (&$this, $request, $view);
243			$controllerObj->controller = $controller;
244			$controllerObj->action = $action;
245			$controllerObj->setViewPath($controller.'/'.$action);
246			$controllerObj->view->baseUrl = $baseUrl;
247			$controllerObj->preDispatch();
248			$controllerObj->$actionMethod();
249			$controllerObj->preDispatch();
250			$output = $controllerObj->render();
251			$controllerObj->cleanup();
252			echo $output;
253		} catch (Sodapop_Database_Exception $e) {
254			if ($e->getCode() == '1005') {
255				// if session timeout, try to kill the session user and reload
256				unset($_SESSION['user']);
257				$this->loadControllerAction($controller, $action, $request, $view, $baseUrl);
258			} else {
259				// otherwise, throw it again
260				throw $e;
261			}
262		}
263		exit();
264	}
265
266	public static function parseIniFile($environment, $config, $applicationRoot) {
267		// load the config
268		$loadOrder = array();
269		switch ($environment){
270			case 'development':
271				$loadOrder[] = 'development';
272			case 'testing':
273				$loadOrder[] = 'testing';
274			case 'production':
275				$loadOrder[] = 'production';
276				break;
277		}
278
279		$newConfig = array();
280		for ($i = count($loadOrder) - 1; $i >= 0; $i--) {
281			foreach($config[$loadOrder[$i]] as $attribute => $value) {
282				$value = str_replace('APPLICATION_ROOT', $applicationRoot, $value);
283				$newConfig[$attribute] = $value;
284			}
285		}
286		if (!isset($newConfig['view.themes.root_directory'])) {
287			$newConfig['view.themes.root_directory'] = $applicationRoot.'/../library/Themes';
288		}
289		if (!isset($newConfig['view.themes.current'])) {
290			$newConfig['view.themes.current'] = 'Monochrome';
291		}
292		if (!isset($newConfig['bootstrap.file_path'])) {
293			$newConfig['bootstrap.file_path'] = $applicationRoot.'/Bootstrap.php';
294		}
295		if (!isset($newConfig['controller.directory'])) {
296			$newConfig['controller.directory'] = $applicationRoot.'/application/controllers';
297		}
298
299		return $newConfig;
300	}
301
302	private function processRoutesFile($routesArray) {
303		$routes = array();
304		foreach ($routesArray as $route) {
305			$urlParts = explode('/', $route['from']);
306			// figure out the key
307			$regex = '/';
308			foreach($urlParts as $part) {
309				if ($regex != '/') {
310					$regex .= '\/';
311				}
312				if (substr($part, 0, 1) == ':') {
313					$regex .= '(?P<'.substr($part, 1).'>[^\/]*)';
314				} else {
315					$regex .= $part;
316				}
317			}
318			$regex .= '/';
319			// add it to the routes array
320			if (isset($route['url'])) {
321				$routes[$regex] = array('url' => $route['url']);
322			} else if ($route['controller']) {
323				$routes[$regex] = array('controller' => $route['controller']);
324				if ($route['action']) {
325					$routes[$regex]['action'] = $route['action'];
326				}
327			}
328		}
329		return $routes;
330	}
331}
332
333/**
334* Most of Sodapop's magic goes through this function.
335*
336* @param string $className
337*/
338function __autoload($className) {
339	$classNameParts = explode('_', $className);
340	@include_once(implode('/', $classNameParts).'.php');
341	if (!class_exists($className)) {
342		// test standard controllers
343		switch ($className) {
344			case 'IndexController':
345				createClass('IndexController', 'Standard_Controller_Index');
346				break;
347			case 'AuthenticationController':
348				createClass('AuthenticationController', 'Standard_Controller_Authentication');
349				break;
350		}
351		if ($_SESSION['user']) {
352			// these only work if there is a user with a connection in the session
353			if (!class_exists($className)) {
354				// start looking for models in the user's table list, then their form list
355				$modelName = (substr($className, 0, 14) == 'Sodapop_Model_' ? substr($className, 14) : $className);
356				if ($_SESSION['user']->hasTablePermission(Sodapop_Inflector::camelCapsToUnderscores($modelName, false), 'SELECT')) {
357					$_SESSION['user']->connection->defineTableClass(Sodapop_Inflector::camelCapsToUnderscores($modelName, false), $className);
358				} else if ($_SESSION['user']->hasFormPermission(Sodapop_Inflector::camelCapsToUnderscores($modelName, false), null, 'VIEW')) {
359					$_SESSION['user']->connection->defineFormClass(Sodapop_Inflector::camelCapsToUnderscores($modelName, false), $className);
360				}
361			}
362			if (!class_exists($className)) {
363				// start looking through the available models to see if we need to instantiate a controller
364				if (substr($className, -10) == 'Controller') {
365					if (in_array(Sodapop_Inflector::camelCapsToUnderscores(substr($className, 0, strlen($className) - 10), false), $_SESSION['user']->availableModels)) {
366						createClass($className, 'Standard_Controller_Model');
367					}
368				}
369
370			}
371		}
372	}
373}
374
375function __unserialize($className) {
376	__autoload($className);
377}
378
379function createClass($className, $extends, $fields = array()) {
380	$classDef = 'class '.$className.' extends '.$extends.' { ';
381	foreach ($fields as $name => $value) {
382		$classDef .' $'.$name.' = "'.$value.'"; ';
383	}
384	$classDef .= '}';
385	eval ($classDef);
386}
387
388function determine_mime_type($filePath, $mimeFile = 'mime.ini') {
389	if (function_exists('finfo_open')) {
390		$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
391		$retval = finfo_file($finfo, $path);
392		finfo_close($finfo);
393		return $retval;
394	} else {
395		$types = parse_ini_file($mimeFile);
396		$extension = substr($filePath, strrpos($filePath, '.') + 1);
397		if (isset($types[$extension])) {
398			return $types[$extension];
399		} else {
400			return 'application/octet-stream';
401		}
402	}
403}