Phly Documentation Phly
Phly_Darcs
[ return to channel ] [ class tree: Phly ] [ index: Phly ] [ all elements ]

Source for file Controller.php

Documentation is available at Controller.php

  1. <?php
  2. /**
  3. * PHLY - PHp LibrarY
  4. *
  5. * PHLY is a library of PHP classes designed with the following intentions:
  6. * - Loosely coupled; dependencies should be few, and no base class should be
  7. * necessary.
  8. * - Extendible; all classes should be easily extendible. This may be via
  9. * observers, interfaces, adapters, etc.. The base class should solve 80% of
  10. * usage, and allow extensions to the class to fill in the remainder.
  11. * - Designed for PHP5 and up; all classes should make use of PHP5's features.
  12. * - Documented; all classes should minimally have excellent API-level
  13. * documentation, with use cases in the class docblock.
  14. * - Tested; all classes should have (passing) unit tests accompanying them.
  15. * - Open source and commercial friendly; all classes should use a
  16. * commercial-friendly open source license. The BSD license is one such
  17. * example.
  18. *
  19. * @license New BSD, http://www.opensource.org/licenses/bsd-license.php
  20. * @package Phly
  21. * @copyright 2006 - Present, Matthew Weier O'Phinney
  22. */
  23.  
  24. /**
  25. * Cgiapp2 controller
  26. */
  27. require_once 'Cgiapp2.class.php';
  28.  
  29. /**
  30. * Use XSLT for templating
  31. */
  32. require_once 'Cgiapp2/Plugin/Xslt.php';
  33.  
  34. /**
  35. * Use darcs model
  36. */
  37. require_once 'Phly/Darcs/Model.php';
  38.  
  39. /**
  40. * Darcs repository browsing class
  41. *
  42. * @todo Ability to PUT to repository
  43. * @package Phly
  44. * @subpackage Phly_Darcs
  45. * @copyright 2006 - Present, Matthew Weier O'Phinney
  46. * @author Matthew Weier O'Phinney <mweierophinney@gmail.com>
  47. * @license BSD
  48. * @version $Id: fsource_Phly_Phly_Darcs_Phly_DarcsPhlyDarcsController.php.html 71 2007-05-12 20:54:24Z matthew $
  49. */
  50. class Phly_Darcs_Controller extends Cgiapp2
  51. {
  52. /**
  53. * Phly_Config object
  54. * @var Phly_Config
  55. * @access public
  56. */
  57. public $config;
  58.  
  59. /**
  60. * Pre-run initialization
  61. *
  62. * Loads configuration from file specified in 'darcs_config' Cgiapp param.
  63. *
  64. * @access public
  65. * @param Cgiapp2 $cgiapp
  66. * @return void
  67. */
  68. public function cgiapp_init($args, Cgiapp2 $cgiapp)
  69. {
  70. if (!$this->param('darcs_config')) {
  71. $cgiapp->croak('Missing darcs config file declaration');
  72. }
  73.  
  74. // Load config
  75. require_once 'Phly/Config.php';
  76. Phly_Config::load($this->param('darcs_config'), 'darcs');
  77. $this->config = Phly_Config::getInstance();
  78. Phly_Darcs_Model::setExecutable($this->config->darcs->exe);
  79. Phly_Darcs_Model::setRepoPath($this->config->darcs->repoPath);
  80. }
  81.  
  82. public function setup()
  83. {
  84. // Setup run modes
  85. $this->run_modes(array(
  86. 'repos' => 'listRepos',
  87. 'browse' => 'browseRepo',
  88. 'annotate' => 'annotate',
  89. 'patch' => 'showPatches',
  90. 'diff' => 'showDiff',
  91. 'rss' => 'showRss'
  92. ));
  93.  
  94. // start mode
  95. $this->start_mode('repos');
  96.  
  97. // error mode
  98. $this->error_mode('showError');
  99.  
  100. // mode param...
  101. if (null === ($idx = $this->config->darcs->index->action)) {
  102. $idx = 1;
  103. }
  104. $this->mode_param(array(
  105. 'path_info' => $idx,
  106. 'param' => 'q'
  107. ));
  108. }
  109.  
  110. /**
  111. * Handle and display errors
  112. *
  113. * @access public
  114. * @param mixed $e
  115. * @return string
  116. */
  117. public function showError($e)
  118. {
  119. $message = 'An error occurred in this application.';
  120. if (is_object($e) && method_exists($e, 'getMessage')) {
  121. $message = $e->getMessage();
  122. } elseif (is_string($e)) {
  123. $message = $e;
  124. }
  125. $output =<<<EOX
  126. <error type="general" title="error">
  127. $message
  128. </error>
  129. EOX;
  130. $xml = Phly_Darcs_Model::xmlWrap($output);
  131.  
  132. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->error));
  133. }
  134.  
  135. /**
  136. * Prerun
  137. *
  138. * Check for presence of certain items, and forward as necessary on absence.
  139. *
  140. * @access public
  141. * @param mixed $rm
  142. * @param Cgiapp2 $cgiapp
  143. * @return void
  144. */
  145. public function cgiapp_prerun($rm, Cgiapp2 $cgiapp)
  146. {
  147. // Pass some info on to the template
  148. $path = strpos($_SERVER['REQUEST_URI'], $rm)
  149. ? substr($_SERVER['REQUEST_URI'], strpos($_SERVER['REQUEST_URI'], $rm) + strlen($rm) + 1)
  150. : $_SERVER['REQUEST_URI'];
  151. if (strpos($path, '?')) {
  152. $path = substr($path, 0, strpos($path, '?'));
  153. }
  154.  
  155. // Get protocol:
  156. $proto = 'http://';
  157. if (isset($_SERVER['HTTPS']) && 'on' == strtolower($_SERVER['HTTPS'])) {
  158. $proto = 'https://';
  159. }
  160. $uri = $proto . $_SERVER['HTTP_HOST'] . $cgiapp->config->darcs->baseUrl;
  161. $cgiapp->tmpl_assign(array(
  162. 'cgi-program' => $uri,
  163. 'cgi-url' => $uri . '/' . $path
  164. ));
  165.  
  166. // Most run modes require a valid repository
  167. if (in_array($rm, array('browse', 'annotate', 'patch', 'diff', 'rss')))
  168. {
  169. if (!$repo = Cgiapp2::path_info($cgiapp->config->darcs->index->repo))
  170. {
  171. // repo not found in path
  172. $cgiapp->prerun_mode('repos');
  173. return;
  174. } else {
  175. // repo does not exist
  176. if (!in_array($repo, array_keys(Phly_Darcs_Model::getRepos())))
  177. {
  178. $cgiapp->prerun_mode('repos');
  179. return;
  180. }
  181. }
  182.  
  183. // Capture the current repository for later...
  184. $cgiapp->param('cur_repo', $repo);
  185. $cgiapp->tmpl_assign('darcs-repo', $repo);
  186. }
  187.  
  188. $this->tmpl_assign('repo-path', $this->_getRqPath());
  189.  
  190. // Capture query string arguments for later
  191. $darcs_args = array();
  192. $q =& self::query();
  193. if (isset($q['p']) && preg_match('/^([\w\-.]+)$/', $q['p'])) {
  194. // patch provided
  195. $darcs_args[] = '--match \'hash ' . $q['p'] . '\'';
  196. }
  197.  
  198. if (isset($q['t']) && preg_match('/^(.+)$/', $q['t'])) {
  199. // tag provided
  200. $darcs_args[] = '--tag ' . $q['t'];
  201. }
  202.  
  203. if (isset($q['ch']) && preg_match('/^([\w\-.]+)$/', $q['ch'])) {
  204. // creator hash provided
  205. $darcs_args[] = '--creator-hash ' . $q['ch'];
  206. }
  207.  
  208. if (isset($q['o']) && preg_match('@^([^\\!\$\^&*()\[\]{}<>~`|\';"?\r\n]+)$@', $q['o'])) {
  209. $cgiapp->param('darcs_orig_path', $q['o']);
  210. }
  211.  
  212. if (0 < count($darcs_args)) {
  213. $cgiapp->param('darcs_args', $darcs_args);
  214. }
  215.  
  216. // Capture sorting information
  217. $sort = '';
  218. if (isset($q['s']) && preg_match('/^(\w+)$/', $q['s'])) {
  219. $sort = $q['s'];
  220. }
  221.  
  222. // Pass sort info on to the template
  223. $cgiapp->tmpl_assign('sort-by', $sort);
  224. }
  225.  
  226. /**
  227. * List available repositories
  228. *
  229. * Creates an XML list of repository directories and passes it on to the
  230. * xslt processor to process.
  231. *
  232. * @access public
  233. * @return string
  234. */
  235. public function listRepos()
  236. {
  237. $xml = Phly_Darcs_Model::listRepos();
  238. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->listRepos));
  239. }
  240.  
  241. /**
  242. * Determine the request path
  243. *
  244. * @access protected
  245. * @return string
  246. */
  247. protected function _getRqPath()
  248. {
  249. if (!$this->param('rq_path')) {
  250. $repo = $this->param('cur_repo');
  251. $rm = $this->get_current_runmode();
  252. $baseDir = $this->config->darcs->repoPath;
  253. $rq = $_SERVER['REQUEST_URI'];
  254. $seed = $rm . '/' . $repo;
  255.  
  256. $path = substr($rq, strpos($rq, $seed) + strlen($seed) + 1);
  257. if (strpos($path, '?')) {
  258. $path = substr($path, 0, strpos($path, '?'));
  259. }
  260.  
  261. $this->param('rq_path', trim($path, '/'));
  262. }
  263.  
  264. return $this->param('rq_path');
  265. }
  266.  
  267. /**
  268. * Browse a repository
  269. *
  270. * @access public
  271. * @return string
  272. */
  273. public function browseRepo()
  274. {
  275. $repo = $this->param('cur_repo');
  276. $rqPath = $this->_getRqPath();
  277. $xml = Phly_Darcs_Model::browseRepo($repo, $rqPath);
  278. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->browse));
  279. }
  280.  
  281. /**
  282. * Show annotations for a file
  283. *
  284. * @access public
  285. * @return string
  286. */
  287. public function annotate()
  288. {
  289. $repo = $this->param('cur_repo');
  290. if (!$rqPath = $this->param('darcs_orig_path')) {
  291. $rqPath = $this->_getRqPath();
  292. }
  293. if (!$darcs_args = $this->param('darcs_args')) {
  294. $darcs_args = '--summary';
  295. } else {
  296. $darcs_args[] = '--summary';
  297. }
  298.  
  299. $xml = Phly_Darcs_Model::execute($repo, 'annotate', $darcs_args, $rqPath);
  300.  
  301. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->annotate));
  302. }
  303.  
  304. /**
  305. * Show patches for a file
  306. *
  307. * @access public
  308. * @return string
  309. */
  310. public function showPatches()
  311. {
  312. $repo = $this->param('cur_repo');
  313. if (!$rqPath = $this->param('darcs_orig_path')) {
  314. $rqPath = $this->_getRqPath();
  315. }
  316. $xml = Phly_Darcs_Model::execute($repo, 'changes', null, $rqPath);
  317. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->patches));
  318. }
  319.  
  320. /**
  321. * Show a diff for a file
  322. *
  323. * @access public
  324. * @return string
  325. */
  326. public function showDiff()
  327. {
  328. $repo = $this->param('cur_repo');
  329. if (!$rqPath = $this->param('darcs_orig_path')) {
  330. $rqPath = $this->_getRqPath();
  331. }
  332.  
  333. if (!$darcs_args = $this->param('darcs_args')) {
  334. throw new Cgiapp2_Exception('Missing patch hash for diff');
  335. } else {
  336. $found = false;
  337. foreach ($darcs_args as $arg) {
  338. if (strstr($arg, '--match \'hash')) {
  339. $found = true;
  340. break;
  341. }
  342. }
  343. if (!$found) {
  344. throw new Cgiapp2_Exception('Missing patch hash for diff');
  345. }
  346. }
  347.  
  348. $xml = Phly_Darcs_Model::execute($repo, 'diff', $darcs_args, $rqPath);
  349.  
  350. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->diff));
  351. }
  352.  
  353. /**
  354. * Show an RSS feed of changes
  355. *
  356. * @access public
  357. * @return string
  358. */
  359. public function showRss()
  360. {
  361. $repo = $this->param('cur_repo');
  362. $rqPath = $this->_getRqPath();
  363. if (null === ($count = $this->config->darcs->rssCount)) {
  364. $count = 10;
  365. }
  366. if (!$darcs_args = $this->param('darcs_args')) {
  367. $darcs_args = '--last ' . $count;
  368. } else {
  369. $darcs_args[] = '--last ' . $count;
  370. }
  371.  
  372. $xml = Phly_Darcs_Model::execute($repo, 'changes', $darcs_args, $rqPath);
  373. $this->header_type('header');
  374. $this->header_props(array('Content-type' => 'text/xml'));
  375. return $this->load_tmpl(array($xml, $this->config->darcs->tmpl->rss));
  376. }
  377. }