PageRenderTime 76ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/src/PHPFrame/Application/Application.php

https://github.com/chrismcband/PHPFrame
PHP | 1013 lines | 511 code | 132 blank | 370 comment | 83 complexity | 62d3db56a806d0791f79d0604f74b47e MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * PHPFrame/Application/Application.php
  4. *
  5. * PHP version 5
  6. *
  7. * @category PHPFrame
  8. * @package Application
  9. * @author Lupo Montero <lupo@e-noise.com>
  10. * @copyright 2010 The PHPFrame Group
  11. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  12. * @link http://github.com/PHPFrame/PHPFrame
  13. */
  14. /**
  15. * The Application class encapsulates all objects that make up the structure
  16. * of an MVC application.
  17. *
  18. * This class is composed mainly of other objects (config, db, features,
  19. * logger, ...) and caches application wide data in a file based "Registry".
  20. *
  21. * The Application class is responsible for initialising an app and dispatching
  22. * requests and thus processing input and output to the application as a whole.
  23. *
  24. * @category PHPFrame
  25. * @package Application
  26. * @author Lupo Montero <lupo@e-noise.com>
  27. * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
  28. * @link http://github.com/PHPFrame/PHPFrame
  29. * @since 1.0
  30. */
  31. class PHPFrame_Application extends PHPFrame_Observer
  32. {
  33. /**
  34. * Absolute path to application in filesystem
  35. *
  36. * @var string
  37. */
  38. private $_install_dir;
  39. /**
  40. * Absolute path to "config" directory. By default this will be a
  41. * subdirectory called "etc" inside install_dir.
  42. *
  43. * @var string
  44. */
  45. private $_config_dir;
  46. /**
  47. * Absolute path to "variable" directory. By default this will be a
  48. * subdirectory called "var" inside install_dir. This is where the app will
  49. * store files (except for configuration and temporary files).
  50. *
  51. * @var string
  52. */
  53. private $_var_dir;
  54. /**
  55. * Absolute path to "temporary" directory. By default this will be a
  56. * subdirectory called "tmp" inside install_dir.
  57. *
  58. * @var string
  59. */
  60. private $_tmp_dir;
  61. /**
  62. * Configuration object
  63. *
  64. * @var PHPFrame_Config
  65. */
  66. private $_config;
  67. /**
  68. * Registry object used to cache application wide objects
  69. *
  70. * @var PHPFrame_FileRegistry
  71. */
  72. private $_registry;
  73. /**
  74. * The Request object the application will handle
  75. *
  76. * @var PHPFrame_Request
  77. */
  78. private $_request;
  79. /**
  80. * The Response object used for the application output
  81. *
  82. * @var PHPFrame_Response
  83. */
  84. private $_response;
  85. /**
  86. * Reference to database object.
  87. *
  88. * @var PHPFrame_Database
  89. */
  90. private $_db;
  91. /**
  92. * An instance of PluginHandler that the application will use to provide
  93. * hooks for plugins.
  94. *
  95. * @var PHPFrame_PluginHandler
  96. */
  97. private $_plugin_handler;
  98. /**
  99. * Instance of MVC factory used to server up userland controllers, models,
  100. * helpers and so on.
  101. *
  102. * @var PHPFrame_MVCFactory
  103. */
  104. private $_mvc_factory;
  105. /**
  106. * A prefix used for MVC userland classes. Default value is empty. This
  107. * affects controllers, models, helpers and language classes.
  108. *
  109. * @var string
  110. */
  111. private $_class_prefix = "";
  112. /**
  113. * Constructor
  114. *
  115. * @param array $options An associative array with the following keys:
  116. * - install_dir [Required]
  117. * - config_dir [Optional]
  118. * - var_dir [Optional]
  119. * - tmp_dir [Optional]
  120. *
  121. * @return void
  122. * @since 1.0
  123. */
  124. public function __construct(array $options)
  125. {
  126. if (!isset($options["install_dir"])) {
  127. $msg = "Otions array passed to ".get_class($this)."::";
  128. $msg .= __FUNCTION__."() must contain 'install_dir' key.";
  129. throw new InvalidArgumentException($msg);
  130. }
  131. if (!is_string($options["install_dir"])) {
  132. $msg = "'install_dir' option passed to ".get_class($this);
  133. $msg .= " must be of type string and value passed of type '";
  134. $msg .= gettype($options["install_dir"])."'.";
  135. throw new InvalidArgumentException($msg);
  136. }
  137. if (!is_dir($options["install_dir"])
  138. || !is_readable($options["install_dir"])
  139. ) {
  140. $msg = "Could not read directory ".$options["install_dir"];
  141. throw new RuntimeException($msg);
  142. }
  143. $this->_install_dir = $options["install_dir"];
  144. $option_keys = array(
  145. "config_dir" => "etc",
  146. "var_dir" => "var",
  147. "tmp_dir" => "tmp"
  148. );
  149. foreach ($option_keys as $key=>$value) {
  150. $prop_name = "_".$key;
  151. if (isset($options[$key]) && !is_null($options[$key])) {
  152. $this->$prop_name = $options[$key];
  153. } else {
  154. $this->$prop_name = $this->_install_dir.DS.$value;
  155. }
  156. if ($key != "config_dir"
  157. && ((!is_dir($this->$prop_name) && !mkdir($this->$prop_name))
  158. || !is_writable($this->$prop_name))
  159. ) {
  160. $msg = "Directory ".$this->$prop_name." is not writable.";
  161. throw new RuntimeException($msg);
  162. }
  163. }
  164. // Throw exception if config file doesn't exist
  165. $config_file = $this->_config_dir.DS."phpframe.ini";
  166. if (!is_file($config_file)) {
  167. $msg = "Config file ".$config_file." not found.";
  168. throw new RuntimeException($msg);
  169. }
  170. // Acquire config object and cache it
  171. $this->config(new PHPFrame_Config($config_file));
  172. // Acquire and store instance of MVC Factory class
  173. $this->factory(new PHPFrame_MVCFactory($this));
  174. // Register Application's autoload function
  175. spl_autoload_register(array($this, "autoload"));
  176. // Attach observers to Exception handler
  177. $logger = $this->logger();
  178. if ($logger instanceof PHPFrame_Logger) {
  179. PHPFrame_ExceptionHandler::instance()->attach($logger);
  180. }
  181. $informer = $this->informer();
  182. if ($informer instanceof PHPFrame_Logger) {
  183. PHPFrame_ExceptionHandler::instance()->attach($informer);
  184. }
  185. PHPFrame_ExceptionHandler::instance()->attach($this);
  186. // Acquire instance of Plugin Handler
  187. $this->_plugin_handler = new PHPFrame_PluginHandler($this);
  188. }
  189. /**
  190. * Application's destructor.
  191. *
  192. * @return void
  193. * @since 1.0
  194. */
  195. public function __destruct()
  196. {
  197. // Register Application's autoload function
  198. spl_autoload_unregister(array($this, "autoload"));
  199. }
  200. /**
  201. * Magic method to autoload application specific classes
  202. *
  203. * This autoloader is registered in {@link PHPFrame_Application::dispatch()}.
  204. *
  205. * @param string $class_name The name of the class to attempt loading.
  206. *
  207. * @return void
  208. * @since 1.0
  209. * @todo Need to look at implementation of classPrefix() feature and how
  210. * it affects the autoloader.
  211. */
  212. public function autoload($class_name)
  213. {
  214. $file_path = $this->getInstallDir().DS."src".DS;
  215. // Autoload Controllers, Helpers and Language classes
  216. $super_classes = array("Controller", "Helper", "Lang");
  217. foreach ($super_classes as $super_class) {
  218. if (preg_match('/'.$super_class.'$/', $class_name)) {
  219. // Set base path for objects of given superclass
  220. $file_path .= strtolower($super_class);
  221. break;
  222. }
  223. }
  224. // Append lang dir based on config for lang classes
  225. if ($super_class == "Lang") {
  226. $file_path .= DS.$this->config()->get("default_lang");
  227. } else {
  228. // Append 's' to dir name except for all others
  229. $file_path .= "s";
  230. }
  231. // Remove superclass name from class name
  232. $class_name = str_replace($super_class, "", $class_name);
  233. // Remove class prefix if applicable
  234. //$class_name = str_replace($this->classPrefix(), "", $class_name);
  235. // Build dir path by breaking camel case class name
  236. $pattern = '/[A-Z]{1}[a-zA-Z0-9]+/';
  237. $matches = array();
  238. preg_match_all($pattern, ucfirst($class_name), $matches);
  239. if (isset($matches[0]) && is_array($matches[0])) {
  240. $file_path .= DS.strtolower(implode(DS, $matches[0]));
  241. }
  242. // Append file extension
  243. $file_path .= ".php";
  244. // require the file if it exists
  245. if (is_file($file_path)) {
  246. include $file_path;
  247. return;
  248. }
  249. // Autoload models
  250. $models_dir = $this->_install_dir.DS."src".DS."models";
  251. if (is_dir($models_dir)) {
  252. $dir_iterator = new RecursiveDirectoryIterator($models_dir);
  253. $filter = array("php");
  254. $iterator = new RecursiveIteratorIterator(
  255. $dir_iterator,
  256. RecursiveIteratorIterator::SELF_FIRST
  257. );
  258. foreach ($iterator as $file) {
  259. $file_split = explode('.', $file->getFileName());
  260. if (in_array(end($file_split), $filter)) {
  261. $file_name_no_ext = substr(
  262. $file->getFileName(),
  263. 0,
  264. strpos($file->getFileName(), ".")
  265. );
  266. if (strtolower($class_name) == strtolower($file_name_no_ext)) {
  267. include $file->getRealPath();
  268. return;
  269. }
  270. }
  271. }
  272. }
  273. // Load libraries
  274. foreach ($this->libraries() as $lib) {
  275. $lib_path = $this->getInstallDir().DS."lib";
  276. $lib_file = $lib_path.DS.$class_name.".php";
  277. if (is_file($lib_file)) {
  278. include $lib_file;
  279. return;
  280. }
  281. }
  282. }
  283. /**
  284. * Implementation of PHPFrame_Observer abstract class.
  285. *
  286. * @param PHPFrame_Subject $subject Reference to instance of subject being
  287. * observed.
  288. *
  289. * @return void
  290. * @since 1.0
  291. */
  292. protected function doUpdate(PHPFrame_Subject $subject)
  293. {
  294. $response = $this->response();
  295. $request = $this->request();
  296. if ($subject instanceof PHPFrame_ExceptionHandler) {
  297. $exception = $subject->lastException();
  298. $code = $exception->getCode();
  299. if (!in_array($code, array(400, 401, 403, 404, 500))) {
  300. $code = 500;
  301. }
  302. if (!$request->param("suppress_response_codes")) {
  303. $response->statusCode($code);
  304. } else {
  305. $response->statusCode(200);
  306. }
  307. $content_type = $response->header("Content-Type");
  308. if (!$request->ajax() && $content_type != "application/json") {
  309. $response->title("Oooops... an error occurred");
  310. }
  311. $display_exceptions = $this->config()->get("debug.display_exceptions");
  312. if ($display_exceptions) {
  313. $response->body($exception);
  314. } else {
  315. switch ($code) {
  316. case 400 :
  317. $msg = "Bad Request";
  318. break;
  319. case 401 :
  320. $msg = "Unauthorised";
  321. break;
  322. case 403 :
  323. $msg = "Forbidden";
  324. break;
  325. case 404 :
  326. $msg = "Not Found";
  327. break;
  328. case 500 :
  329. $msg = "Internal Server Error";
  330. break;
  331. }
  332. $response->body(new Exception($msg, $code));
  333. }
  334. $this->output();
  335. exit($code);
  336. }
  337. }
  338. /**
  339. * Get absolute path to installation directory
  340. *
  341. * @return string
  342. * @since 1.0
  343. */
  344. public function getInstallDir()
  345. {
  346. return $this->_install_dir;
  347. }
  348. /**
  349. * Get absolute path to var directory
  350. *
  351. * @return string
  352. * @since 1.0
  353. */
  354. public function getVarDir()
  355. {
  356. return $this->_var_dir;
  357. }
  358. /**
  359. * Get absolute path to tmp directory
  360. *
  361. * @return string
  362. * @since 1.0
  363. */
  364. public function getTmpDir()
  365. {
  366. return $this->_tmp_dir;
  367. }
  368. /**
  369. * Get/set configuration object.
  370. *
  371. * @param PHPFrame_Config $config [Optional] The new configuration object
  372. * to use in the application.
  373. *
  374. * @return PHPFrame_Config
  375. * @since 1.0
  376. */
  377. public function config(PHPFrame_Config $config=null)
  378. {
  379. if (!is_null($config)) {
  380. $this->_setConfig($config);
  381. }
  382. return $this->_config;
  383. }
  384. /**
  385. * Get reference to application's session object.
  386. *
  387. * @return PHPFrame_SessionRegistry
  388. * @since 1.0
  389. */
  390. public function session()
  391. {
  392. return PHPFrame::getSession($this->config()->get("base_url"));
  393. }
  394. /**
  395. * Get reference to session's user object.
  396. *
  397. * @return PHPFrame_User
  398. * @since 1.0
  399. */
  400. public function user()
  401. {
  402. return $this->session()->getUser();
  403. }
  404. /**
  405. * Get/set Request object.
  406. *
  407. * @param PHPFrame_Request $request [Optional] Request object.
  408. *
  409. * @return PHPFrame_Request
  410. * @since 1.0
  411. */
  412. public function request(PHPFrame_Request $request=null)
  413. {
  414. if (!is_null($request)) {
  415. $this->_request = $request;
  416. } elseif (is_null($this->_request)) {
  417. // Create new request
  418. $request = new PHPFrame_Request();
  419. // populate request using client
  420. $this->session()->getClient()->populateRequest($request);
  421. $this->_request = $request;
  422. }
  423. return $this->_request;
  424. }
  425. /**
  426. * Get/set Response object.
  427. *
  428. * @param PHPFrame_Response $response [Optional] Response object.
  429. *
  430. * @return PHPFrame_Response
  431. * @since 1.0
  432. */
  433. public function response(PHPFrame_Response $response=null)
  434. {
  435. if (!is_null($response)) {
  436. $this->_response = $response;
  437. } elseif (is_null($this->_response)) {
  438. // Create new response object
  439. $response = new PHPFrame_Response();
  440. $response->header(
  441. "Content-Language",
  442. $this->config()->get("default_lang")
  443. );
  444. // Prepare response using client
  445. $client = $this->session()->getClient();
  446. $views_path = $this->getInstallDir().DS."src".DS."views";
  447. $client->prepareResponse($response, $views_path);
  448. $this->_response = $response;
  449. }
  450. return $this->_response;
  451. }
  452. /**
  453. * Get/set Registry object
  454. *
  455. * The registry object is used to cache all application objects that are
  456. * shared across the whole app. This registry is itself automatically
  457. * cached to file during garbage collection.
  458. *
  459. * @param PHPFrame_FileRegistry $file_registry [Optional] A file registry
  460. * object used to cache
  461. * application wide data to
  462. * file.
  463. *
  464. * @return PHPFrame_FileRegistry
  465. * @since 1.0
  466. */
  467. public function registry(PHPFrame_FileRegistry $file_registry=null)
  468. {
  469. if (!is_null($file_registry)) {
  470. $this->_registry = $file_registry;
  471. } elseif (is_null($this->_registry)) {
  472. $cache_file = $this->_tmp_dir.DS."app.reg";
  473. $this->_registry = new PHPFrame_FileRegistry($cache_file);
  474. }
  475. return $this->_registry;
  476. }
  477. /**
  478. * Get/set database object.
  479. *
  480. * @param PHPFrame_Database $db [Optional] Instance of PHPFrame_Database.
  481. *
  482. * @return PHPFrame_Database
  483. * @since 1.0
  484. */
  485. public function db(PHPFrame_Database $db=null)
  486. {
  487. if (!is_null($db)) {
  488. $this->_db = $db;
  489. } elseif (is_null($this->_db)) {
  490. $options = $this->config()->getSection("db");
  491. if (!array_key_exists("enable", $options) || !$options["enable"]) {
  492. $msg = "Can not get database object because database is not ";
  493. $msg .= "enabled in configuration file.";
  494. throw new LogicException($msg);
  495. }
  496. if (!array_key_exists("driver", $options)
  497. || !array_key_exists("name", $options)
  498. ) {
  499. $msg = "'driver' and 'name' are required in options array";
  500. throw new InvalidArgumentException($msg);
  501. }
  502. // Make absolute path for sqlite db if relative given
  503. if (strtolower($options["driver"]) == "sqlite"
  504. && !preg_match('/^\//', $options["name"])
  505. ) {
  506. $options["name"] = $this->_var_dir.DS.$options["name"];
  507. }
  508. $this->_db = PHPFrame_DatabaseFactory::getDB($options);
  509. }
  510. return $this->_db;
  511. }
  512. /**
  513. * Get/set Mailer object
  514. *
  515. * @param PHPFrame_Mailer $mailer Mailer object.
  516. *
  517. * @return PHPFrame_Mailer
  518. * @since 1.0
  519. */
  520. public function mailer(PHPFrame_Mailer $mailer=null)
  521. {
  522. if (!is_null($mailer)) {
  523. $this->registry()->set("mailer", $mailer);
  524. } elseif (is_null($this->registry()->get("mailer"))
  525. && $this->config()->get("smtp.enable")
  526. ) {
  527. $options = $this->config()->getSection("smtp");
  528. $mailer = new PHPFrame_Mailer($options);
  529. $this->registry()->set("mailer", $mailer);
  530. }
  531. return $this->registry()->get("mailer");
  532. }
  533. /**
  534. * Get/set IMAP object used for incoming email.
  535. *
  536. * @param PHPFrame_IMAP $imap [Optional] IMAP object.
  537. *
  538. * @return PHPFrame_IMAP
  539. * @since 1.0
  540. */
  541. public function imap(PHPFrame_IMAP $imap=null)
  542. {
  543. $imap_enabled = (bool) $this->config()->get("imap.enable");
  544. if (!is_null($imap)) {
  545. $this->registry()->set("imap", $imap);
  546. } elseif (is_null($this->registry()->get("imap")) && $imap_enabled) {
  547. $this->registry()->set(
  548. "imap",
  549. new PHPFrame_IMAP(
  550. $this->config()->get("imap.host"),
  551. $this->config()->get("imap.user"),
  552. $this->config()->get("imap.pass")
  553. )
  554. );
  555. }
  556. return $this->registry()->get("imap");
  557. }
  558. /**
  559. * Get/set Libraries object.
  560. *
  561. * @param PHPFrame_Libraries $libraries [Optional] Libraries object.
  562. *
  563. * @return PHPFrame_Libraries
  564. * @since 1.0
  565. */
  566. public function libraries(PHPFrame_Libraries $libraries=null)
  567. {
  568. if (!is_null($libraries)) {
  569. $this->registry()->set("libraries", $libraries);
  570. } elseif (is_null($this->registry()->get("libraries"))) {
  571. // Create mapper for PHPFrame_LibInfo object
  572. $mapper = new PHPFrame_Mapper(
  573. "PHPFrame_LibInfo",
  574. $this->_config_dir,
  575. "lib"
  576. );
  577. $this->registry()->set("libraries", new PHPFrame_Libraries($mapper));
  578. }
  579. return $this->_registry->get("libraries");
  580. }
  581. /**
  582. * Get/set Plugins object.
  583. *
  584. * @param PHPFrame_Plugins $plugins [Optional] Plugins object.
  585. *
  586. * @return PHPFrame_Plugins
  587. * @since 1.0
  588. */
  589. public function plugins(PHPFrame_Plugins $plugins=null)
  590. {
  591. if (!is_null($plugins)) {
  592. $this->registry()->set("plugins", $plugins);
  593. } elseif (is_null($this->registry()->get("plugins"))) {
  594. // Create mapper for PHPFrame_Plugins object
  595. $mapper = new PHPFrame_Mapper(
  596. "PHPFrame_PluginInfo",
  597. $this->_config_dir,
  598. "plugins"
  599. );
  600. $this->registry()->set("plugins", new PHPFrame_Plugins($mapper));
  601. }
  602. return $this->_registry->get("plugins");
  603. }
  604. /**
  605. * Get/set Logger object.
  606. *
  607. * @param PHPFrame_Logger $logger [Optional] Logger object to be used in
  608. * application.
  609. *
  610. * @return PHPFrame_Logger
  611. * @since 1.0
  612. */
  613. public function logger(PHPFrame_Logger $logger=null)
  614. {
  615. $log_level = $this->config()->get("debug.log_level");
  616. if ($log_level <= 0) {
  617. return;
  618. }
  619. if (!is_null($logger)) {
  620. $this->_setLogger($logger);
  621. } elseif (is_null($this->registry()->get("logger"))) {
  622. $logger = new PHPFrame_TextLogger(
  623. $this->_var_dir.DS."app.log",
  624. $log_level
  625. );
  626. $this->registry()->set("logger", $logger);
  627. }
  628. return $this->registry()->get("logger");
  629. }
  630. /**
  631. * Get/set Informer object.
  632. *
  633. * @param PHPFrame_Informer $informer [Optional] Informer object to be used
  634. * in application.
  635. *
  636. * @return PHPFrame_Informer
  637. * @since 1.0
  638. */
  639. public function informer(PHPFrame_Informer $informer=null)
  640. {
  641. $informer_level = $this->config()->get("debug.informer_level");
  642. if ($informer_level <= 0) {
  643. return;
  644. }
  645. if (!is_null($informer)) {
  646. $this->_setInformer($informer);
  647. } elseif (is_null($this->registry()->get("informer"))) {
  648. // Create informer
  649. $recipients = $this->config()->get("debug.informer_recipients");
  650. $recipients = explode(",", $recipients);
  651. $mailer = $this->mailer();
  652. if (!$mailer instanceof PHPFrame_Mailer) {
  653. $msg = "Can not create informer object. No mailer has been ";
  654. $msg .= "loaded in application. Please check the 'smtp' ";
  655. $msg .= "section in the config file.";
  656. throw new LogicException($msg);
  657. }
  658. $this->registry()->set(
  659. "informer",
  660. new PHPFrame_Informer($mailer, $recipients, $informer_level)
  661. );
  662. }
  663. return $this->registry()->get("informer");
  664. }
  665. /**
  666. * Get/set Crypt object.
  667. *
  668. * @param PHPFrame_Crypt $crypt [Optional]
  669. *
  670. * @return PHPFrame_Crypt
  671. * @since 1.0
  672. */
  673. public function crypt(PHPFrame_Crypt $crypt=null)
  674. {
  675. if (!is_null($crypt)) {
  676. $this->registry()->set("crypt", $crypt);
  677. } elseif (is_null($this->registry()->get("crypt"))) {
  678. $secret = $this->config()->get("secret");
  679. $this->registry()->set("crypt", new PHPFrame_Crypt($secret));
  680. }
  681. return $this->registry()->get("crypt");
  682. }
  683. /**
  684. * Get/set reference to MVC factory object.
  685. *
  686. * @param PHPFrame_MVCFactory $mvc_factory [Optional] Reference to
  687. * PHPFrame_MVCFactory object.
  688. *
  689. * @return PHPFrame_MVCFactory
  690. * @since 1.0
  691. */
  692. public function factory(PHPFrame_MVCFactory $mvc_factory=null)
  693. {
  694. if (!is_null($mvc_factory)) {
  695. $this->_mvc_factory = $mvc_factory;
  696. }
  697. return $this->_mvc_factory;
  698. }
  699. /**
  700. * Get/set the userland class prefix.
  701. *
  702. * @param string $str [Optional] The new class suffix.
  703. *
  704. * @return string
  705. * @since 1.0
  706. */
  707. public function classPrefix($str=null)
  708. {
  709. if (!is_null($str)) {
  710. $this->_class_prefix = trim((string) $str);
  711. }
  712. return $this->_class_prefix;
  713. }
  714. /**
  715. * Dispatch request
  716. *
  717. * @param PHPFrame_Request $request [Optional] If omitted a new request
  718. * object will be created using the data
  719. * provided by the session client.
  720. *
  721. * @return void
  722. * @since 1.0
  723. */
  724. public function dispatch(PHPFrame_Request $request=null)
  725. {
  726. // If no request is passed we try to use request object cached in app
  727. // or a new request is created using the session's client
  728. if (is_null($request)) {
  729. $request = $this->request();
  730. } else {
  731. $this->request($request);
  732. }
  733. // Register installed plugins with plugin handler
  734. foreach ($this->plugins() as $plugin) {
  735. if ($plugin->enabled()) {
  736. $plugin_name = $plugin->name();
  737. $this->_plugin_handler->registerPlugin(new $plugin_name($this));
  738. }
  739. }
  740. // Invoke route startup hook before request object is initialised
  741. $this->_plugin_handler->handle("routeStartup");
  742. // If no controller has been set we use de default value provided in
  743. // etc/phpframe.ini
  744. $controller_name = $request->controllerName();
  745. if (is_null($controller_name) || empty($controller_name)) {
  746. $def_controller = $this->config()->get("default_controller");
  747. $request->controllerName($def_controller);
  748. }
  749. // Invoke route shutdown hook
  750. $this->_plugin_handler->handle("routeShutdown");
  751. // Invoke dispatchLoopStartup hook
  752. $this->_plugin_handler->handle("dispatchLoopStartup");
  753. while (!$request->dispatched()) {
  754. // Set request as dispatched
  755. $request->dispatched(true);
  756. // Invoke preDispatch hook for every iteration of the dispatch loop
  757. $this->_plugin_handler->handle("preDispatch");
  758. // If any plugin set dispatched to false we start a new iteration
  759. if (!$request->dispatched()) {
  760. $request->dispatched(true);
  761. continue;
  762. }
  763. // Get requested controller name
  764. $controller_name = $request->controllerName();
  765. // Create the action controller
  766. $mvc_factory = $this->factory();
  767. $controller = $mvc_factory->getActionController($controller_name);
  768. // Attach observers to the action controller
  769. $controller->attach($this->session()->getSysevents());
  770. $log_level = $this->config()->get("debug.log_level");
  771. if ($log_level > 0) {
  772. $controller->attach($this->logger());
  773. }
  774. $informer_level = $this->config()->get("debug.informer_level");
  775. if ($informer_level > 0) {
  776. $controller->attach($this->informer());
  777. }
  778. // Execute the action in the given controller
  779. $controller->execute();
  780. // Invoke postDispatch hook for every iteration of the dispatch loop
  781. $this->_plugin_handler->handle("postDispatch");
  782. // Redirect if set in controller
  783. $status_code = $this->response()->statusCode();
  784. $redirect_url = $this->response()->header("Location");
  785. if (in_array($status_code, array(301, 303, 307))) {
  786. if (!$redirect_url) {
  787. $msg = "HTTP status code was set to ".$status_code." but ";
  788. $msg .= "no redirect URL was specified in the Location ";
  789. $msg .= "header.";
  790. throw new LogicException($msg);
  791. }
  792. $this->session()->getClient()->redirect($redirect_url);
  793. return;
  794. }
  795. }
  796. // Invoke dispatchLoopShutdown hook
  797. $this->_plugin_handler->handle("dispatchLoopShutdown");
  798. $this->output();
  799. }
  800. /**
  801. * Process response and send output.
  802. *
  803. * @return void
  804. * @since 1.0
  805. */
  806. protected function output()
  807. {
  808. $request = $this->request();
  809. $response = $this->response();
  810. // Invoke dispatchLoopShutdown hook
  811. $this->_plugin_handler->handle("preApplyTheme");
  812. // Apply theme if needed
  813. $document = $response->document();
  814. $renderer = $response->renderer();
  815. $sysevents = $this->session()->getSysevents();
  816. if ($document instanceof PHPFrame_HTMLDocument) {
  817. if (!$request->ajax()) {
  818. $theme = $this->config()->get("theme");
  819. $base_url = $this->config()->get("base_url");
  820. $theme_url = $base_url."themes/".$theme;
  821. $theme_path = $this->getInstallDir().DS."public".DS."themes";
  822. $theme_path .= DS.$theme.DS."index.php";
  823. $document->applyTheme($theme_url, $theme_path, $this);
  824. } else {
  825. // Append system events when no theme
  826. // $document->prependBody($renderer->render($sysevents));
  827. // $sysevents->clear();
  828. // Set "body only" mode for AJAX requests when HTML document
  829. $document->bodyOnly(true);
  830. }
  831. } elseif ($renderer instanceof PHPFrame_RPCRenderer) {
  832. if (count($sysevents) > 0) {
  833. $sysevents->statusCode($response->statusCode());
  834. $renderer->render($sysevents);
  835. }
  836. }
  837. // Invoke postApplyTheme hook
  838. $this->_plugin_handler->handle("postApplyTheme");
  839. // If not in quiet mode, send response back to the client
  840. if (!$request->quiet()) {
  841. $response->send();
  842. }
  843. // If outfile is defined we write the response to file
  844. $outfile = $request->outfile();
  845. if (!empty($outfile)) {
  846. $file_obj = new SplFileObject($outfile, "w");
  847. $file_obj->fwrite((string) $response);
  848. }
  849. }
  850. /**
  851. * Set configuration object
  852. *
  853. * @param PHPFrame_Config $config The new configuration object to use in
  854. * the application.
  855. *
  856. * @return void
  857. * @since 1.0
  858. */
  859. private function _setConfig(PHPFrame_Config $config)
  860. {
  861. // Check that config object has required data
  862. $array = iterator_to_array($config);
  863. $req_keys = array("app_name", "base_url");
  864. foreach ($req_keys as $req_key) {
  865. if (!isset($array[$req_key]) || empty($array[$req_key])) {
  866. $msg = "Could not set configuration object. Config must ";
  867. $msg .= "contain a value for '".$req_key."'. ";
  868. $msg .= "To set this configuration parameter you can edit ";
  869. $msg .= "the configuration file stored in ";
  870. $msg .= "'".$config->getPath()."'.";
  871. throw new RuntimeException($msg);
  872. }
  873. }
  874. $this->_config = $config;
  875. // Set timezone
  876. date_default_timezone_set($config->get("timezone"));
  877. // Set display_exceptions in exception handler
  878. $display_exceptions = $config->get("debug.display_exceptions");
  879. PHPFrame_ExceptionHandler::displayExceptions($display_exceptions);
  880. }
  881. }