diff options
Diffstat (limited to 'application/render')
-rw-r--r-- | application/render/PageBuilder.php | 114 | ||||
-rw-r--r-- | application/render/PageCacheManager.php | 60 | ||||
-rw-r--r-- | application/render/TemplatePage.php | 34 |
3 files changed, 161 insertions, 47 deletions
diff --git a/application/render/PageBuilder.php b/application/render/PageBuilder.php index f4fefda8..c2fae705 100644 --- a/application/render/PageBuilder.php +++ b/application/render/PageBuilder.php | |||
@@ -3,10 +3,12 @@ | |||
3 | namespace Shaarli\Render; | 3 | namespace Shaarli\Render; |
4 | 4 | ||
5 | use Exception; | 5 | use Exception; |
6 | use Psr\Log\LoggerInterface; | ||
6 | use RainTPL; | 7 | use RainTPL; |
7 | use Shaarli\ApplicationUtils; | ||
8 | use Shaarli\Bookmark\BookmarkServiceInterface; | 8 | use Shaarli\Bookmark\BookmarkServiceInterface; |
9 | use Shaarli\Config\ConfigManager; | 9 | use Shaarli\Config\ConfigManager; |
10 | use Shaarli\Helper\ApplicationUtils; | ||
11 | use Shaarli\Security\SessionManager; | ||
10 | use Shaarli\Thumbnailer; | 12 | use Shaarli\Thumbnailer; |
11 | 13 | ||
12 | /** | 14 | /** |
@@ -33,6 +35,9 @@ class PageBuilder | |||
33 | */ | 35 | */ |
34 | protected $session; | 36 | protected $session; |
35 | 37 | ||
38 | /** @var LoggerInterface */ | ||
39 | protected $logger; | ||
40 | |||
36 | /** | 41 | /** |
37 | * @var BookmarkServiceInterface $bookmarkService instance. | 42 | * @var BookmarkServiceInterface $bookmarkService instance. |
38 | */ | 43 | */ |
@@ -52,23 +57,40 @@ class PageBuilder | |||
52 | * PageBuilder constructor. | 57 | * PageBuilder constructor. |
53 | * $tpl is initialized at false for lazy loading. | 58 | * $tpl is initialized at false for lazy loading. |
54 | * | 59 | * |
55 | * @param ConfigManager $conf Configuration Manager instance (reference). | 60 | * @param ConfigManager $conf Configuration Manager instance (reference). |
56 | * @param array $session $_SESSION array | 61 | * @param array $session $_SESSION array |
57 | * @param BookmarkServiceInterface $linkDB instance. | 62 | * @param LoggerInterface $logger |
58 | * @param string $token Session token | 63 | * @param null $linkDB instance. |
59 | * @param bool $isLoggedIn | 64 | * @param null $token Session token |
65 | * @param bool $isLoggedIn | ||
60 | */ | 66 | */ |
61 | public function __construct(&$conf, $session, $linkDB = null, $token = null, $isLoggedIn = false) | 67 | public function __construct( |
62 | { | 68 | ConfigManager &$conf, |
69 | array $session, | ||
70 | LoggerInterface $logger, | ||
71 | $linkDB = null, | ||
72 | $token = null, | ||
73 | $isLoggedIn = false | ||
74 | ) { | ||
63 | $this->tpl = false; | 75 | $this->tpl = false; |
64 | $this->conf = $conf; | 76 | $this->conf = $conf; |
65 | $this->session = $session; | 77 | $this->session = $session; |
78 | $this->logger = $logger; | ||
66 | $this->bookmarkService = $linkDB; | 79 | $this->bookmarkService = $linkDB; |
67 | $this->token = $token; | 80 | $this->token = $token; |
68 | $this->isLoggedIn = $isLoggedIn; | 81 | $this->isLoggedIn = $isLoggedIn; |
69 | } | 82 | } |
70 | 83 | ||
71 | /** | 84 | /** |
85 | * Reset current state of template rendering. | ||
86 | * Mostly useful for error handling. We remove everything, and display the error template. | ||
87 | */ | ||
88 | public function reset(): void | ||
89 | { | ||
90 | $this->tpl = false; | ||
91 | } | ||
92 | |||
93 | /** | ||
72 | * Initialize all default tpl tags. | 94 | * Initialize all default tpl tags. |
73 | */ | 95 | */ |
74 | private function initialize() | 96 | private function initialize() |
@@ -87,7 +109,7 @@ class PageBuilder | |||
87 | $this->tpl->assign('newVersion', escape($version)); | 109 | $this->tpl->assign('newVersion', escape($version)); |
88 | $this->tpl->assign('versionError', ''); | 110 | $this->tpl->assign('versionError', ''); |
89 | } catch (Exception $exc) { | 111 | } catch (Exception $exc) { |
90 | logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage()); | 112 | $this->logger->error(format_log('Error: ' . $exc->getMessage(), client_ip_id($_SERVER))); |
91 | $this->tpl->assign('newVersion', ''); | 113 | $this->tpl->assign('newVersion', ''); |
92 | $this->tpl->assign('versionError', escape($exc->getMessage())); | 114 | $this->tpl->assign('versionError', escape($exc->getMessage())); |
93 | } | 115 | } |
@@ -126,7 +148,7 @@ class PageBuilder | |||
126 | $this->tpl->assign('language', $this->conf->get('translation.language')); | 148 | $this->tpl->assign('language', $this->conf->get('translation.language')); |
127 | 149 | ||
128 | if ($this->bookmarkService !== null) { | 150 | if ($this->bookmarkService !== null) { |
129 | $this->tpl->assign('tags', $this->bookmarkService->bookmarksCountPerTag()); | 151 | $this->tpl->assign('tags', escape($this->bookmarkService->bookmarksCountPerTag())); |
130 | } | 152 | } |
131 | 153 | ||
132 | $this->tpl->assign( | 154 | $this->tpl->assign( |
@@ -136,18 +158,45 @@ class PageBuilder | |||
136 | $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width')); | 158 | $this->tpl->assign('thumbnails_width', $this->conf->get('thumbnails.width')); |
137 | $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height')); | 159 | $this->tpl->assign('thumbnails_height', $this->conf->get('thumbnails.height')); |
138 | 160 | ||
139 | if (!empty($_SESSION['warnings'])) { | ||
140 | $this->tpl->assign('global_warnings', $_SESSION['warnings']); | ||
141 | unset($_SESSION['warnings']); | ||
142 | } | ||
143 | |||
144 | $this->tpl->assign('formatter', $this->conf->get('formatter', 'default')); | 161 | $this->tpl->assign('formatter', $this->conf->get('formatter', 'default')); |
145 | 162 | ||
163 | $this->tpl->assign('links_per_page', $this->session['LINKS_PER_PAGE'] ?? 20); | ||
164 | |||
146 | // To be removed with a proper theme configuration. | 165 | // To be removed with a proper theme configuration. |
147 | $this->tpl->assign('conf', $this->conf); | 166 | $this->tpl->assign('conf', $this->conf); |
148 | } | 167 | } |
149 | 168 | ||
150 | /** | 169 | /** |
170 | * Affect variable after controller processing. | ||
171 | * Used for alert messages. | ||
172 | */ | ||
173 | protected function finalize(string $basePath): void | ||
174 | { | ||
175 | // TODO: use the SessionManager | ||
176 | $messageKeys = [ | ||
177 | SessionManager::KEY_SUCCESS_MESSAGES, | ||
178 | SessionManager::KEY_WARNING_MESSAGES, | ||
179 | SessionManager::KEY_ERROR_MESSAGES | ||
180 | ]; | ||
181 | foreach ($messageKeys as $messageKey) { | ||
182 | if (!empty($_SESSION[$messageKey])) { | ||
183 | $this->tpl->assign('global_' . $messageKey, $_SESSION[$messageKey]); | ||
184 | unset($_SESSION[$messageKey]); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | $rootPath = preg_replace('#/index\.php$#', '', $basePath); | ||
189 | $this->assign('base_path', $basePath); | ||
190 | $this->assign('root_path', $rootPath); | ||
191 | $this->assign( | ||
192 | 'asset_path', | ||
193 | $rootPath . '/' . | ||
194 | rtrim($this->conf->get('resource.raintpl_tpl', 'tpl'), '/') . '/' . | ||
195 | $this->conf->get('resource.theme', 'default') | ||
196 | ); | ||
197 | } | ||
198 | |||
199 | /** | ||
151 | * The following assign() method is basically the same as RainTPL (except lazy loading) | 200 | * The following assign() method is basically the same as RainTPL (except lazy loading) |
152 | * | 201 | * |
153 | * @param string $placeholder Template placeholder. | 202 | * @param string $placeholder Template placeholder. |
@@ -185,21 +234,6 @@ class PageBuilder | |||
185 | } | 234 | } |
186 | 235 | ||
187 | /** | 236 | /** |
188 | * Render a specific page (using a template file). | ||
189 | * e.g. $pb->renderPage('picwall'); | ||
190 | * | ||
191 | * @param string $page Template filename (without extension). | ||
192 | */ | ||
193 | public function renderPage($page) | ||
194 | { | ||
195 | if ($this->tpl === false) { | ||
196 | $this->initialize(); | ||
197 | } | ||
198 | |||
199 | $this->tpl->draw($page); | ||
200 | } | ||
201 | |||
202 | /** | ||
203 | * Render a specific page as string (using a template file). | 237 | * Render a specific page as string (using a template file). |
204 | * e.g. $pb->render('picwall'); | 238 | * e.g. $pb->render('picwall'); |
205 | * | 239 | * |
@@ -207,28 +241,14 @@ class PageBuilder | |||
207 | * | 241 | * |
208 | * @return string Processed template content | 242 | * @return string Processed template content |
209 | */ | 243 | */ |
210 | public function render(string $page): string | 244 | public function render(string $page, string $basePath): string |
211 | { | 245 | { |
212 | if ($this->tpl === false) { | 246 | if ($this->tpl === false) { |
213 | $this->initialize(); | 247 | $this->initialize(); |
214 | } | 248 | } |
215 | 249 | ||
216 | return $this->tpl->draw($page, true); | 250 | $this->finalize($basePath); |
217 | } | ||
218 | 251 | ||
219 | /** | 252 | return $this->tpl->draw($page, true); |
220 | * Render a 404 page (uses the template : tpl/404.tpl) | ||
221 | * usage: $PAGE->render404('The link was deleted') | ||
222 | * | ||
223 | * @param string $message A message to display what is not found | ||
224 | */ | ||
225 | public function render404($message = '') | ||
226 | { | ||
227 | if (empty($message)) { | ||
228 | $message = t('The page you are trying to reach does not exist or has been deleted.'); | ||
229 | } | ||
230 | header($_SERVER['SERVER_PROTOCOL'] . ' ' . t('404 Not Found')); | ||
231 | $this->tpl->assign('error_message', $message); | ||
232 | $this->renderPage('404'); | ||
233 | } | 253 | } |
234 | } | 254 | } |
diff --git a/application/render/PageCacheManager.php b/application/render/PageCacheManager.php new file mode 100644 index 00000000..97805c35 --- /dev/null +++ b/application/render/PageCacheManager.php | |||
@@ -0,0 +1,60 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Shaarli\Render; | ||
4 | |||
5 | use Shaarli\Feed\CachedPage; | ||
6 | |||
7 | /** | ||
8 | * Cache utilities | ||
9 | */ | ||
10 | class PageCacheManager | ||
11 | { | ||
12 | /** @var string Cache directory */ | ||
13 | protected $pageCacheDir; | ||
14 | |||
15 | /** @var bool */ | ||
16 | protected $isLoggedIn; | ||
17 | |||
18 | public function __construct(string $pageCacheDir, bool $isLoggedIn) | ||
19 | { | ||
20 | $this->pageCacheDir = $pageCacheDir; | ||
21 | $this->isLoggedIn = $isLoggedIn; | ||
22 | } | ||
23 | |||
24 | /** | ||
25 | * Purges all cached pages | ||
26 | * | ||
27 | * @return string|null an error string if the directory is missing | ||
28 | */ | ||
29 | public function purgeCachedPages(): ?string | ||
30 | { | ||
31 | if (!is_dir($this->pageCacheDir)) { | ||
32 | $error = sprintf(t('Cannot purge %s: no directory'), $this->pageCacheDir); | ||
33 | error_log($error); | ||
34 | |||
35 | return $error; | ||
36 | } | ||
37 | |||
38 | array_map('unlink', glob($this->pageCacheDir . '/*.cache')); | ||
39 | |||
40 | return null; | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * Invalidates caches when the database is changed or the user logs out. | ||
45 | */ | ||
46 | public function invalidateCaches(): void | ||
47 | { | ||
48 | // Purge page cache shared by sessions. | ||
49 | $this->purgeCachedPages(); | ||
50 | } | ||
51 | |||
52 | public function getCachePage(string $pageUrl): CachedPage | ||
53 | { | ||
54 | return new CachedPage( | ||
55 | $this->pageCacheDir, | ||
56 | $pageUrl, | ||
57 | false === $this->isLoggedIn | ||
58 | ); | ||
59 | } | ||
60 | } | ||
diff --git a/application/render/TemplatePage.php b/application/render/TemplatePage.php new file mode 100644 index 00000000..03b424f3 --- /dev/null +++ b/application/render/TemplatePage.php | |||
@@ -0,0 +1,34 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Shaarli\Render; | ||
6 | |||
7 | interface TemplatePage | ||
8 | { | ||
9 | public const ERROR_404 = '404'; | ||
10 | public const ADDLINK = 'addlink'; | ||
11 | public const CHANGE_PASSWORD = 'changepassword'; | ||
12 | public const CHANGE_TAG = 'changetag'; | ||
13 | public const CONFIGURE = 'configure'; | ||
14 | public const DAILY = 'daily'; | ||
15 | public const DAILY_RSS = 'dailyrss'; | ||
16 | public const EDIT_LINK = 'editlink'; | ||
17 | public const EDIT_LINK_BATCH = 'editlink.batch'; | ||
18 | public const ERROR = 'error'; | ||
19 | public const EXPORT = 'export'; | ||
20 | public const NETSCAPE_EXPORT_BOOKMARKS = 'export.bookmarks'; | ||
21 | public const FEED_ATOM = 'feed.atom'; | ||
22 | public const FEED_RSS = 'feed.rss'; | ||
23 | public const IMPORT = 'import'; | ||
24 | public const INSTALL = 'install'; | ||
25 | public const LINKLIST = 'linklist'; | ||
26 | public const LOGIN = 'loginform'; | ||
27 | public const OPEN_SEARCH = 'opensearch'; | ||
28 | public const PICTURE_WALL = 'picwall'; | ||
29 | public const PLUGINS_ADMIN = 'pluginsadmin'; | ||
30 | public const TAG_CLOUD = 'tag.cloud'; | ||
31 | public const TAG_LIST = 'tag.list'; | ||
32 | public const THUMBNAILS = 'thumbnails'; | ||
33 | public const TOOLS = 'tools'; | ||
34 | } | ||