PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/PieCrust/Page/Page.php

https://bitbucket.org/ndj/piecrust
PHP | 414 lines | 272 code | 41 blank | 101 comment | 35 complexity | 413d67b9084a1848f894c93252c0b4f1 MD5 | raw file
  1. <?php
  2. namespace PieCrust\Page;
  3. use \Exception;
  4. use \InvalidArgumentException;
  5. use PieCrust\IPage;
  6. use PieCrust\IPieCrust;
  7. use PieCrust\PieCrustException;
  8. use PieCrust\Data\DataBuilder;
  9. use PieCrust\IO\Cache;
  10. use PieCrust\Util\PieCrustHelper;
  11. use PieCrust\Util\UriParser;
  12. use PieCrust\Util\UriBuilder;
  13. /**
  14. * A class that represents a page (article or post) in PieCrust.
  15. *
  16. */
  17. class Page implements IPage
  18. {
  19. protected $pieCrust;
  20. /**
  21. * Gets the PieCrust app this page belongs to.
  22. */
  23. public function getApp()
  24. {
  25. return $this->pieCrust;
  26. }
  27. protected $path;
  28. /**
  29. * Gets the file-system path to the page's file.
  30. */
  31. public function getPath()
  32. {
  33. return $this->path;
  34. }
  35. protected $uri;
  36. /**
  37. * Gets the PieCrust URI to the page.
  38. */
  39. public function getUri()
  40. {
  41. return $this->uri;
  42. }
  43. protected $blogKey;
  44. /**
  45. * Gets the blog key for this page.
  46. */
  47. public function getBlogKey()
  48. {
  49. return $this->blogKey;
  50. }
  51. protected $pageNumber;
  52. /**
  53. * Gets the page number (for pages that display a large number of posts).
  54. */
  55. public function getPageNumber()
  56. {
  57. return $this->pageNumber;
  58. }
  59. /**
  60. * Sets the page number.
  61. */
  62. public function setPageNumber($pageNumber)
  63. {
  64. if ($pageNumber != $this->pageNumber)
  65. {
  66. $this->pageNumber = $pageNumber;
  67. $this->unload();
  68. }
  69. }
  70. protected $key;
  71. /**
  72. * Gets the page key (e.g. the tag or category)
  73. */
  74. public function getPageKey()
  75. {
  76. return $this->key;
  77. }
  78. /**
  79. * Sets the page key (e.g. the tag or category)
  80. */
  81. public function setPageKey($key)
  82. {
  83. if ($key != $this->key)
  84. {
  85. $this->key = $key;
  86. $this->unload();
  87. }
  88. }
  89. protected $date;
  90. protected $dateIsLocked;
  91. /**
  92. * Gets the date (and possibly time) this page was created.
  93. *
  94. * This loads the page's configuration, unless the date was already
  95. * specifically set with `setDate` (which is the case for blog posts
  96. * for example).
  97. */
  98. public function getDate()
  99. {
  100. if ($this->date === null or !$this->dateIsLocked)
  101. {
  102. // Get the date from the file on disk if it was never set.
  103. // Override with the date from the config if authorized to do so.
  104. $dateFromConfig = $this->getConfig()->getValue('date');
  105. if ($dateFromConfig != null)
  106. $this->date = strtotime($dateFromConfig);
  107. else if ($this->date === null)
  108. $this->date = filemtime($this->path);
  109. // Add/adjust the time of day if needed.
  110. $timeFromConfig = $this->getConfig()->getValue('time');
  111. if ($timeFromConfig != null)
  112. $this->date = strtotime($timeFromConfig, $this->date);
  113. // Lock the date.
  114. $this->dateIsLocked = true;
  115. }
  116. return $this->date;
  117. }
  118. /**
  119. * Sets the date this page was created.
  120. */
  121. public function setDate($date, $isLocked = false)
  122. {
  123. if ($date !==null && $this->date != $date)
  124. {
  125. if (is_int($date))
  126. {
  127. $this->date = $date;
  128. $this->dateIsLocked = $isLocked;
  129. }
  130. else if (is_string($date))
  131. {
  132. $this->date = strtotime($date);
  133. $this->dateIsLocked = $isLocked;
  134. }
  135. else
  136. {
  137. throw new PieCrustException("The date must be an number or a string.");
  138. }
  139. }
  140. }
  141. protected $type;
  142. /**
  143. * Gets the page type.
  144. */
  145. public function getPageType()
  146. {
  147. return $this->type;
  148. }
  149. protected $wasCached;
  150. /**
  151. * Gets whether this page's contents were cached.
  152. */
  153. public function wasCached()
  154. {
  155. return $this->wasCached;
  156. }
  157. protected $config;
  158. /**
  159. * Gets the page's configuration from its YAML header.
  160. */
  161. public function getConfig()
  162. {
  163. $this->ensureConfigLoaded();
  164. return $this->config;
  165. }
  166. protected $contents;
  167. protected $formattedContents;
  168. /**
  169. * Gets the page's formatted content.
  170. */
  171. public function getContentSegment($segment = 'content')
  172. {
  173. $this->ensureContentsFormatted();
  174. return $this->formattedContents[$segment];
  175. }
  176. /**
  177. * Returns whether a given content segment exists.
  178. */
  179. public function hasContentSegment($segment)
  180. {
  181. $this->ensureContentsFormatted();
  182. return isset($this->formattedContents[$segment]);
  183. }
  184. /**
  185. * Gets all the page's formatted content segments.
  186. */
  187. public function getContentSegments()
  188. {
  189. $this->ensureContentsFormatted();
  190. return $this->formattedContents;
  191. }
  192. protected $pageData;
  193. /**
  194. * Gets the data used for rendering the page.
  195. */
  196. public function getPageData()
  197. {
  198. if ($this->pageData == null)
  199. {
  200. $this->pageData = DataBuilder::getPageData($this);
  201. }
  202. return $this->pageData;
  203. }
  204. protected $extraData;
  205. /**
  206. * Gets the extra data.
  207. */
  208. public function getExtraPageData()
  209. {
  210. return $this->extraData;
  211. }
  212. /**
  213. * Adds extra data to the page's data for rendering.
  214. */
  215. public function setExtraPageData(array $data)
  216. {
  217. $this->unload();
  218. $this->extraData = $data;
  219. }
  220. protected $assetUrlBaseRemap;
  221. /**
  222. * Gets the asset URL base remapping pattern.
  223. */
  224. public function getAssetUrlBaseRemap()
  225. {
  226. return $this->assetUrlBaseRemap;
  227. }
  228. /**
  229. * Sets the asset URL base remapping pattern.
  230. */
  231. public function setAssetUrlBaseRemap($remap)
  232. {
  233. $this->assetUrlBaseRemap = $remap;
  234. }
  235. protected $paginationDataSource;
  236. /**
  237. * Gets the pagination data source.
  238. */
  239. public function getPaginationDataSource()
  240. {
  241. return $this->paginationDataSource;
  242. }
  243. /**
  244. * Sets the pagination data source.
  245. */
  246. public function setPaginationDataSource($postInfos)
  247. {
  248. $this->paginationDataSource = $postInfos;
  249. }
  250. /**
  251. * Unloads the page.
  252. */
  253. public function unload()
  254. {
  255. $this->pageData = null;
  256. $this->formattedContents = null;
  257. }
  258. /**
  259. * Creates a new Page instance.
  260. */
  261. public function __construct(IPieCrust $pieCrust, $uri, $path, $pageType = IPage::TYPE_REGULAR, $blogKey = null, $pageKey = null, $pageNumber = 1, $date = null)
  262. {
  263. $this->pieCrust = $pieCrust;
  264. $this->uri = $uri;
  265. $this->path = $path;
  266. $this->type = $pageType;
  267. $this->blogKey = $blogKey;
  268. $this->key = $pageKey;
  269. $this->pageNumber = $pageNumber;
  270. $this->date = $date;
  271. $this->dateIsLocked = false;
  272. $this->pageData = null;
  273. $this->config = null;
  274. $this->contents = null;
  275. $this->formattedContents = null;
  276. }
  277. /**
  278. * Ensures the page has been loaded from disk.
  279. */
  280. protected function ensureConfigLoaded()
  281. {
  282. if ($this->config == null)
  283. {
  284. // Set the configuration to an empty array so that the PageLoader
  285. // can call 'set()' on it and assign the actual configuration.
  286. $this->config = new PageConfiguration($this, array(), false);
  287. $loader = new PageLoader($this);
  288. $this->contents = $loader->load();
  289. $this->wasCached = $loader->wasCached();
  290. $this->formattedContents = null;
  291. }
  292. }
  293. /**
  294. * Ensures the page has been formatted completely.
  295. */
  296. protected function ensureContentsFormatted()
  297. {
  298. if ($this->formattedContents == null)
  299. {
  300. $this->ensureConfigLoaded();
  301. $loader = new PageLoader($this);
  302. $this->formattedContents = $loader->formatContents($this->contents);
  303. }
  304. }
  305. /**
  306. * Creates a new Page instance given a fully qualified URI.
  307. */
  308. public static function createFromUri(IPieCrust $pieCrust, $uri, $useRepository = true)
  309. {
  310. if ($uri == null)
  311. throw new InvalidArgumentException("The given URI is null.");
  312. $uriInfo = UriParser::parseUri($pieCrust, $uri);
  313. if ($uriInfo == null or
  314. (!$uriInfo['was_path_checked'] and !is_file($uriInfo['path']))
  315. )
  316. {
  317. if ($uriInfo['type'] == IPage::TYPE_TAG)
  318. throw new PieCrustException("Tried to show posts with tag '{$uriInfo['key']}' but the special tag listing page was not found.");
  319. if ($uriInfo['type'] == IPage::TYPE_CATEGORY)
  320. throw new PieCrustException("Tried to show the posts in category '{$uriInfo['key']}' but the special category listing page was not found.");
  321. throw new PieCrustException('404');
  322. }
  323. if ($useRepository)
  324. {
  325. $pageRepository = $pieCrust->getEnvironment()->getPageRepository();
  326. $page = $pageRepository->getOrCreatePage(
  327. $uriInfo['uri'],
  328. $uriInfo['path'],
  329. $uriInfo['type'],
  330. $uriInfo['blogKey']
  331. );
  332. $page->setPageKey($uriInfo['key']);
  333. $page->setPageNumber($uriInfo['page']);
  334. $page->setDate($uriInfo['date']);
  335. return $page;
  336. }
  337. else
  338. {
  339. return new Page(
  340. $pieCrust,
  341. $uriInfo['uri'],
  342. $uriInfo['path'],
  343. $uriInfo['type'],
  344. $uriInfo['blogKey'],
  345. $uriInfo['key'],
  346. $uriInfo['page'],
  347. $uriInfo['date']
  348. );
  349. }
  350. }
  351. /**
  352. * Creates a new Page instance given a path.
  353. */
  354. public static function createFromPath(IPieCrust $pieCrust, $path, $pageType = IPage::TYPE_REGULAR, $pageNumber = 1, $blogKey = null, $pageKey = null, $date = null)
  355. {
  356. if ($path == null)
  357. throw new InvalidArgumentException("The given path is null.");
  358. if (!is_file($path))
  359. throw new InvalidArgumentException("The given path does not exist: " . $path);
  360. $relativePath = PieCrustHelper::getRelativePath($pieCrust, $path, true);
  361. $uri = UriBuilder::buildUri($pieCrust, $relativePath);
  362. return new Page(
  363. $pieCrust,
  364. $uri,
  365. $path,
  366. $pageType,
  367. $blogKey,
  368. $pageKey,
  369. $pageNumber,
  370. $date
  371. );
  372. }
  373. }