Passed
Push — main ( 95dbf1...07579e )
by Marc
03:17
created

get_menu()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 2
rs 10
1
<?php declare(strict_types=1);
2
3
use html_go\exceptions\InternalException;
4
use html_go\i18n\I18n;
5
use html_go\indexing\IndexManager;
6
use html_go\markdown\MarkdownParser;
7
use html_go\markdown\ParsedownParser;
8
use html_go\model\Config;
9
use html_go\model\ModelFactory;
10
use html_go\templating\TemplateEngine;
11
use html_go\templating\TwigTemplateEngine;
12
13
/**
14
 * Returns an multi-dimensional array. The first level is the menu name, the
15
 * second level is an array of stdClass objects each representing a menu node.
16
 * @return array<mixed>
17
 */
18
function get_menus(): array {
19
    return get_index_manager()->getMenusIndex();
20
}
21
22
/**
23
 * Returns the page number from the query string (if there is one).
24
 * @return int Default value is one (1)
25
 */
26
function get_pagination_pagenumber(): int {
27
    $pageNum = 1;
28
    if (($page = get_query_parameter('page')) !== null && \ctype_digit($page)) {
29
        $pageNum = (int)$page;
30
    }
31
    return $pageNum;
32
}
33
34
/**
35
 * Returns a pagination page of tags.
36
 * @param int $pageNum The page number
37
 * @param int $perPage Items per page. Default is 0 (zero) which means return all
38
 * @return array<\stdClass>
39
 */
40
function get_tags(int $pageNum = 1, int $perPage = 0): array {
41
    $tags = get_index_manager()->getTagIndex();
42
    if ($perPage > 0) {
43
        $tags = \array_slice($tags, ($pageNum - 1) * $perPage, $perPage);
44
    }
45
    return get_model_list_from_index($tags);
46
}
47
48
/**
49
 * Returns a pagination page of categories.
50
 * @param int $pageNum The page number
51
 * @param int $perPage Items per page. Default is 0 (zero) which means return all
52
 * @return array<\stdClass> The resulting list of posts
53
 */
54
function get_categories(int $pageNum = 1, int $perPage = 0): array {
55
    $cats = get_index_manager()->getCategoriesIndex();
56
    if ($perPage > 0) {
57
        $cats = \array_slice($cats, ($pageNum - 1) * $perPage, $perPage);
58
    }
59
    return get_model_list_from_index($cats);
60
}
61
62
/**
63
 * Takes an array of index objects (<code>stdClass</code>) and converts them to an array of
64
 * <code>stdClass</code> content objects.
65
 * @param array<string, \stdClass> $indexList
66
 * @return array<\stdClass>
67
 */
68
function get_model_list_from_index(array $indexList): array {
69
    $list = [];
70
    $factory = get_model_factory();
71
    foreach ($indexList as $obj) {
72
        $list[] = $factory->createContentObject($obj);
73
    }
74
    return $list;
75
}
76
77
/**
78
 * Takes an array of URIs (<code>string</code>) and translates them to an array of
79
 * <code>stdClass</code> content objects.
80
 * @param array<string> $uris
81
 * @return array<\stdClass>
82
 */
83
function get_model_list_from_uris(array $uris): array {
84
    $manager = get_index_manager();
85
    $factory = get_model_factory();
86
    $list = [];
87
    foreach ($uris as $slug) {
88
        $indexElement = $manager->getElementFromSlugIndex($slug);
89
        $list[] = $factory->createContentObject($indexElement);
90
    }
91
    return $list;
92
}
93
94
/**
95
 * Build and return the template context.
96
 * @param \stdClass $content
97
 * @return array<mixed>
98
 */
99
function get_template_context(\stdClass $content): array {
100
    $template = DEFAULT_TEMPLATE;
101
    if (isset($content->template)) {
102
        $template = $content->template;
103
    }
104
    return [
105
        'widgets' => get_widgets(),
106
        'i18n' => get_i18n(),
107
        'content' => $content,
108
        TEMPLATE_TPLVAR_KEY => $template
109
    ];
110
}
111
112
/**
113
 * Return the <code>i18n</code> instance.
114
 * @return I18n
115
 */
116
function get_i18n(): I18n {
117
    static $object = null;
118
    if (empty($object)) {
119
        $object = new I18n(LANG_ROOT.DS.get_config()->getString(Config::KEY_LANG).'.messages.php');
120
    }
121
    return $object;
122
}
123
124
/**
125
 * Render the given template placing the given variables into the template context.
126
 * Note: template defined in the front matter of the content file takes precendence.
127
 * @param string $template Default is <code>null</code>
128
 * @param array<mixed> $vars
129
 * @return string
130
 */
131
function render(string $template = null, array $vars = []): string {
132
    $tpl = SINGLE_TEMPLATE;
133
    if (!empty($template)) {
134
        $tpl = $template;
135
    }
136
    // Front matter from content file takes precendence
137
    if (isset($vars[TEMPLATE_TPLVAR_KEY])) {
138
        $tpl = $vars[TEMPLATE_TPLVAR_KEY];
139
    }
140
    return get_template_engine()->render($tpl, $vars);
141
}
142
143
/**
144
 * Helper function for 404 page.
145
 * @return string
146
 */
147
function not_found(): string {
148
    //FIXME: no $content object in the context!!!
149
    return render('404.html', ['i18n' => get_i18n()]);
150
}
151
152
/**
153
 * Get the configured template engine.
154
 * @return TemplateEngine
155
 */
156
function get_template_engine(): TemplateEngine {
157
    static $engine = null;
158
    if (empty($engine)) {
159
        $themeName = get_config()->getString(Config::KEY_THEME_NAME);
160
        $engineName = get_config()->getString(Config::KEY_TPL_ENGINE);
161
162
        switch ($engineName) {
163
            case 'twig':
164
                $engine = build_twig_template_engine($themeName);
165
                break;
166
            case 'smarty':
167
            case 'php':
168
                throw new InternalException("Implement template engine [$engineName]");
169
            default:
170
                throw new \InvalidArgumentException("Unsupported template engine [$engineName]");
171
        }
172
    }
173
    return $engine;
174
}
175
176
/**
177
 * Build the twig template engine.
178
 * @param string $themeName The name of the configure theme
179
 * @return TemplateEngine
180
 */
181
function build_twig_template_engine(string $themeName): TemplateEngine {
182
    $caching = false;
183
    if (get_config()->getBool(Config::KEY_TPL_CACHING)) {
184
        $caching = TEMPLATE_CACHE_ROOT;
185
    }
186
    $strict = get_config()->getBool(Config::KEY_TPL_STRICT_VARS_TWIG);
187
    $options = [
188
        'cache' => $caching,
189
        'strict_variables' => $strict
190
    ];
191
    $templateDirs = [THEMES_ROOT.DS.'twig'.DS.$themeName];
192
    return new TwigTemplateEngine($templateDirs, $options);
193
}
194
195
/**
196
 * Returns the instance of the <code>IndexManager</code>.
197
 * @return IndexManager
198
 */
199
function get_index_manager(): IndexManager {
200
    static $manager = null;
201
    if ($manager === null) {
202
        $manager = new IndexManager(APP_ROOT);
203
    }
204
    return $manager;
205
}
206
207
/**
208
 * Return the instance of the <code>Config</code>.
209
 * @return Config
210
 */
211
function get_config(): Config {
212
    static $config = null;
213
    if (empty($config)) {
214
        $config = new Config(CONFIG_ROOT);
215
    }
216
    return $config;
217
}
218
219
/**
220
 * Returns the instance of the <code>ModelFactory</code>.
221
 * @return ModelFactory
222
 */
223
function get_model_factory(): ModelFactory {
224
    static $factory = null;
225
    if (empty($factory)) {
226
        $factory = new ModelFactory(get_config(), get_markdown_parser(), get_index_manager());
227
    }
228
    return $factory;
229
}
230
231
/**
232
 * Returns the instance of the <code>MarkdownParser</code>.
233
 * @return MarkdownParser
234
 */
235
function get_markdown_parser(): MarkdownParser {
236
    static $parser = null;
237
    if (empty($parser)) {
238
        $parser = new ParsedownParser();
239
    }
240
    return $parser;
241
}
242
243
/**
244
 * Get a <code>Content</code> object (if any) associated with the given slug.
245
 * @param string $slug
246
 * @param array<\stdClass> $list List of <code>Content</code> for this <code>Content</code> object.
247
 * @param string $template
248
 * @return \stdClass|NULL if no content was found associated with the given slug <code>null</code> is returned.
249
 */
250
function get_content_object(string $slug, array $list = [], string $template = DEFAULT_TEMPLATE): ?\stdClass {
251
    $manager = get_index_manager();
252
    if ($manager->elementExists($slug) === false) {
253
        return null;
254
    }
255
    $content = get_model_factory()->createContentObject($manager->getElementFromSlugIndex($slug));
256
    if (empty($list) === false) {
257
        $content->list = $list;
258
    }
259
    $content->menus = get_menus();
260
    if ($content !== null && empty($content->template)) {
261
        $content->template = $template;
262
    }
263
    return $content;
264
}
265
266
/**
267
 * Returns a pagination page of posts.
268
 * @param int $pageNum The page number
269
 * @param int $perPage Items per page
270
 * @return array<\stdClass> The resulting list of posts
271
 */
272
function get_posts(int $pageNum = 1, int $perPage = 5): array {
273
    $posts = get_index_manager()->getPostsIndex();
274
    $posts = \array_slice($posts, ($pageNum - 1) * $perPage, $perPage);
275
    $list = [];
276
    $factory = get_model_factory();
277
    foreach ($posts as $post) {
278
        $list[] = $factory->createContentObject($post);
279
    }
280
    return $list;
281
}
282
283
/**
284
 * Checks if the given slug exists in the index manager (alias for <code>IndexManager::elementExists()</code>).
285
 * @param string $slug
286
 * @return bool
287
 */
288
function slug_exists(string $slug): bool {
289
    return get_index_manager()->elementExists($slug);
290
}
291
292
/**
293
 * Returns a list of widgets
294
 * @return array<mixed>
295
 */
296
function get_widgets(): array {
297
    return [
298
        'recent_posts' => get_posts(),
299
        'category_list' => get_categories(),
300
        'tag_list' => get_tags()
301
    ];
302
}
303
304
/**
305
 * Returns an array of post objects for the given category URI.
306
 * @param string $uri
307
 * @param int $pageNum
308
 * @param int $perPage
309
 * @throws InternalException
310
 * @return array<\stdClass>
311
 */
312
function get_posts_for_category(string $uri, int $pageNum = 1, int $perPage = 5): array {
313
    $manager = get_index_manager();
314
    if ($manager->elementExists($uri) === false) {
315
        throw new InternalException("Category does not exist [$uri]");
316
    }
317
    $posts = $manager->getPostsForCategoryIndex()[$uri];
318
    $posts = \array_slice($posts, ($pageNum - 1) * $perPage, $perPage);
319
    return get_model_list_from_uris($posts);
320
}
321
322
/**
323
 * Returns an array of post object for the given tag URI.
324
 * @param string $uri
325
 * @param int $pageNum
326
 * @param int $perPage
327
 * @throws InternalException
328
 * @return array<\stdClass>
329
 */
330
function get_posts_for_tag(string $uri, int $pageNum = 1, int $perPage = 5): array {
331
    $manager = get_index_manager();
332
    if ($manager->elementExists($uri) === false) {
333
        throw new InternalException("Tag does not exist [$uri]");
334
    }
335
    $tags = $manager->getPostsForTagIndex()[$uri];
336
    $tags = \array_slice($tags, ($pageNum - 1) * $perPage, $perPage);
337
    return get_model_list_from_uris($tags);
338
}
339