/src/PieCrust/PieCrust.php

https://bitbucket.org/ndj/piecrust · PHP · 380 lines · 303 code · 26 blank · 51 comment · 25 complexity · 4be6cf0ecca04b66accd678925556ea0 MD5 · raw file

  1. <?php
  2. namespace PieCrust;
  3. use \Exception;
  4. use PieCrust\Environment\CachedEnvironment;
  5. use PieCrust\Formatters\IFormatter;
  6. use PieCrust\Page\Page;
  7. use PieCrust\Plugins\PluginLoader;
  8. use PieCrust\Util\PathHelper;
  9. use PieCrust\Util\PieCrustHelper;
  10. /**
  11. * The main PieCrust application class.
  12. *
  13. * This class contains the application's configuration and directory setup information,
  14. * and handles, among other things, routing and errors.
  15. */
  16. class PieCrust implements IPieCrust
  17. {
  18. protected $rootDir;
  19. /**
  20. * The root directory of the website.
  21. */
  22. public function getRootDir()
  23. {
  24. return $this->rootDir;
  25. }
  26. protected $cachingEnabled;
  27. /**
  28. * Gets whether caching is enabled.
  29. */
  30. public function isCachingEnabled()
  31. {
  32. return $this->cachingEnabled;
  33. }
  34. protected $debuggingEnabled;
  35. /**
  36. * Gets whether debugging is enabled.
  37. */
  38. public function isDebuggingEnabled()
  39. {
  40. return $this->debuggingEnabled;
  41. }
  42. protected $templatesDirs;
  43. /**
  44. * Gets the directories that contain templates and layouts ('/_content/templates' by default).
  45. */
  46. public function getTemplatesDirs()
  47. {
  48. if ($this->templatesDirs === null)
  49. {
  50. // Start with no template directories.
  51. $this->templatesDirs = array();
  52. // Add the custom template directories specified in the configuration.
  53. $additionalPaths = $this->getConfig()->getValue('site/templates_dirs');
  54. if ($additionalPaths)
  55. {
  56. $this->addTemplatesDir($additionalPaths);
  57. }
  58. // Add the default template directory if it exists.
  59. $default = $this->rootDir . PieCrustDefaults::CONTENT_TEMPLATES_DIR;
  60. if (is_dir($default))
  61. $this->templatesDirs[] = $default;
  62. }
  63. return $this->templatesDirs;
  64. }
  65. /**
  66. * Sets the directories that contain templates and layouts. Directories can be
  67. * relative to the site's root directory.
  68. */
  69. public function setTemplatesDirs($dir)
  70. {
  71. $this->templatesDirs = array();
  72. $this->addTemplatesDir($dir);
  73. }
  74. /**
  75. * Adds a templates directory. It can be relative to the site's root directory.
  76. */
  77. public function addTemplatesDir($dir)
  78. {
  79. $this->getTemplatesDirs(); // Ensure defaults are created.
  80. if (!is_array($dir))
  81. $dir = array($dir);
  82. foreach ($dir as $d)
  83. {
  84. $absolute = PathHelper::getAbsolutePath($d, $this->getRootDir());
  85. if (is_dir($absolute) === false)
  86. {
  87. throw new PieCrustException("The specified templates directory doesn't exist: " . $absolute);
  88. }
  89. $this->templatesDirs[] = rtrim($absolute, '/\\') . '/';
  90. }
  91. }
  92. protected $pagesDir;
  93. /**
  94. * Gets the directory that contains the pages and their assets ('/_content/pages' by default).
  95. */
  96. public function getPagesDir()
  97. {
  98. if ($this->pagesDir === null)
  99. {
  100. $this->pagesDir = $this->rootDir . PieCrustDefaults::CONTENT_PAGES_DIR;
  101. if (!is_dir($this->pagesDir))
  102. $this->pagesDir = false;
  103. }
  104. return $this->pagesDir;
  105. }
  106. /**
  107. * Sets the directory that contains the pages and their assets.
  108. */
  109. public function setPagesDir($dir)
  110. {
  111. $this->pagesDir = rtrim($dir, '/\\') . '/';
  112. if (is_dir($this->pagesDir) === false)
  113. {
  114. throw new PieCrustException("The specified pages directory doesn't exist: " . $this->pagesDir);
  115. }
  116. }
  117. protected $postsDir;
  118. /**
  119. * Gets the directory that contains the posts and their assets ('/_content/posts' by default).
  120. */
  121. public function getPostsDir()
  122. {
  123. if ($this->postsDir === null)
  124. {
  125. $this->postsDir = $this->rootDir . PieCrustDefaults::CONTENT_POSTS_DIR;
  126. if (!is_dir($this->postsDir))
  127. $this->postsDir = false;
  128. }
  129. return $this->postsDir;
  130. }
  131. /**
  132. * Sets the directory that contains the posts and their assets.
  133. */
  134. public function setPostsDir($dir)
  135. {
  136. $this->postsDir = rtrim($dir, '/\\') . '/';
  137. if (is_dir($this->postsDir) === false)
  138. {
  139. throw new PieCrustException("The specified posts directory doesn't exist: " . $this->postsDir);
  140. }
  141. }
  142. protected $pluginsDirs;
  143. /**
  144. * Gets the directories that contain the user plugins.
  145. */
  146. public function getPluginsDirs()
  147. {
  148. if ($this->pluginsDirs === null)
  149. {
  150. // Add the default plugins directory if it exists.
  151. $this->pluginsDirs = array();
  152. $default = $this->rootDir . PieCrustDefaults::CONTENT_PLUGINS_DIR;
  153. if (is_dir($default))
  154. $this->pluginsDirs[] = $default;
  155. // Add custom plugin directories specified in the configuration.
  156. $additionalPaths = $this->getConfig()->getValue('site/plugins_dirs');
  157. if ($additionalPaths)
  158. {
  159. $this->addPluginsDir($additionalPaths);
  160. }
  161. }
  162. return $this->pluginsDirs;
  163. }
  164. /**
  165. * Sets the directories that contain the user plugins.
  166. */
  167. public function setPluginsDirs($dir)
  168. {
  169. $this->pluginsDirs = array();
  170. $this->addPluginsDir($dir);
  171. }
  172. /**
  173. * Adds a directory that contains some user plugins.
  174. */
  175. public function addPluginsDir($dir)
  176. {
  177. $this->getPluginsDirs(); // Ensure defaults are created.
  178. if (!is_array($dir))
  179. $dir = array($dir);
  180. foreach ($dir as $d)
  181. {
  182. $absolute = PathHelper::getAbsolutePath($d, $this->getRootDir());
  183. if (is_dir($absolute) === false)
  184. {
  185. throw new PieCrustException("The specified plugins directory doesn't exist: " . $absolute);
  186. }
  187. $this->pluginsDirs[] = rtrim($absolute, '/\\') . '/';
  188. }
  189. }
  190. protected $themeDir;
  191. /**
  192. * Gets the directory that contains the current theme, if any.
  193. */
  194. public function getThemeDir()
  195. {
  196. if ($this->themeDir === null)
  197. {
  198. $this->themeDir = $this->rootDir . PieCrustDefaults::CONTENT_THEME_DIR;
  199. if (!is_dir($this->themeDir))
  200. $this->themeDir = false;
  201. }
  202. return $this->themeDir;
  203. }
  204. /**
  205. * Sets the directory that contains the current theme, if any.
  206. */
  207. public function setThemeDir($dir)
  208. {
  209. $this->themeDir = rtrim($dir, '/\\') . '/';
  210. if (is_dir($this->themeDir) === false)
  211. {
  212. throw new PieCrustException("The specified theme directory doesn't exist: " . $this->themeDir);
  213. }
  214. }
  215. protected $cacheDir;
  216. /**
  217. * Gets the cache directory ('/_cache' by default).
  218. */
  219. public function getCacheDir()
  220. {
  221. if ($this->cacheDir === null)
  222. {
  223. if ($this->cachingEnabled)
  224. $this->setCacheDir($this->rootDir . PieCrustDefaults::CACHE_DIR);
  225. else
  226. $this->cacheDir = false;
  227. }
  228. return $this->cacheDir;
  229. }
  230. /**
  231. * Sets the cache directory ('/_cache' by default).
  232. */
  233. public function setCacheDir($dir)
  234. {
  235. $this->cacheDir = rtrim($dir, '/\\') . '/';
  236. if (is_writable($this->cacheDir) === false)
  237. {
  238. try
  239. {
  240. if (!is_dir($this->cacheDir))
  241. {
  242. mkdir($dir, 0777, true);
  243. }
  244. else
  245. {
  246. chmod($this->cacheDir, 0777);
  247. }
  248. }
  249. catch (Exception $e)
  250. {
  251. throw new PieCrustException("The cache directory must exist and be writable, and we can't create it or change the permissions ourselves: " . $this->cacheDir);
  252. }
  253. }
  254. }
  255. protected $pluginLoader;
  256. /**
  257. * Gets the plugin loader for this app.
  258. */
  259. public function getPluginLoader()
  260. {
  261. return $this->pluginLoader;
  262. }
  263. protected $config;
  264. /**
  265. * Gets the application's configuration.
  266. */
  267. public function getConfig()
  268. {
  269. $this->ensureConfig();
  270. return $this->config;
  271. }
  272. protected $environment;
  273. /**
  274. * Gets the applicaiton's execution environment.
  275. */
  276. public function getEnvironment()
  277. {
  278. return $this->environment;
  279. }
  280. /**
  281. * Creates a new PieCrust instance with the given base URL.
  282. */
  283. public function __construct(array $parameters = array())
  284. {
  285. $parameters = array_merge(
  286. array(
  287. 'root' => null,
  288. 'cache' => true,
  289. 'debug' => false,
  290. 'environment' => null
  291. ),
  292. $parameters
  293. );
  294. if (!$parameters['root'])
  295. throw new PieCrustException("No root directory was specified.");
  296. $this->rootDir = rtrim($parameters['root'], '/\\') . '/';
  297. $this->debuggingEnabled = (bool)$parameters['debug'];
  298. $this->cachingEnabled = (bool)$parameters['cache'];
  299. $this->pluginLoader = new PluginLoader($this);
  300. $this->environment = $parameters['environment'];
  301. if (!$this->environment)
  302. $this->environment = new CachedEnvironment();
  303. $this->environment->initialize($this);
  304. }
  305. /**
  306. * Ensures the configuration has been loaded.
  307. */
  308. protected function ensureConfig()
  309. {
  310. if ($this->config == null)
  311. {
  312. $configCache = $this->cachingEnabled ? $this->getCacheDir() : false;
  313. $configPaths = array();
  314. $themeDir = $this->getThemeDir();
  315. if ($themeDir !== false)
  316. $configPaths[] = $themeDir . PieCrustDefaults::THEME_CONFIG_PATH;
  317. $configPaths[] = $this->rootDir . PieCrustDefaults::CONFIG_PATH;
  318. $this->config = new PieCrustConfiguration($configPaths, $configCache);
  319. if ($themeDir !== false)
  320. {
  321. // We'll need to patch the templates directories to be relative
  322. // to the site's root, as opposed to the theme root.
  323. $relativeThemeDir = PieCrustHelper::getRelativePath($this, $themeDir);
  324. $this->config->setFixup(function ($i, &$c) use ($relativeThemeDir) {
  325. if ($i == 0)
  326. {
  327. if (!isset($c['site']))
  328. return;
  329. if (!isset($c['site']['templates_dirs']))
  330. return;
  331. if (!is_array($c['site']['templates_dirs']))
  332. $c['site']['templates_dirs'] = array($c['site']['templates_dirs']);
  333. foreach ($c['site']['templates_dirs'] as &$dir)
  334. {
  335. $dir = $relativeThemeDir . $dir;
  336. }
  337. }
  338. });
  339. }
  340. }
  341. }
  342. }