Test Failed
Push — main ( 85dc75...69348d )
by Marc
04:00
created

get_posts_for_section()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 14
c 1
b 0
f 0
nc 4
nop 4
dl 0
loc 19
rs 9.7998
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 array<mixed> $vars
128
 * @return string
129
 */
130
function render(array $vars = []): string {
131
    $tpl = SINGLE_TEMPLATE;
132
    // Front matter from content file takes precendence
133
    if (isset($vars[TEMPLATE_TPLVAR_KEY])) {
134
        $tpl = $vars[TEMPLATE_TPLVAR_KEY];
135
    }
136
    return get_template_engine()->render($tpl, $vars);
137
}
138
139
/**
140
 * Helper function for 404 page.
141
 */
142
function not_found(): string {
143
    header('Location: '.get_config()->getString(Config::KEY_SITE_URL).FWD_SLASH.'not-found');
144
    return '';
145
}
146
147
/**
148
 * Get the configured template engine.
149
 * @return TemplateEngine
150
 */
151
function get_template_engine(): TemplateEngine {
152
    static $engine = null;
153
    if (empty($engine)) {
154
        $themeName = get_config()->getString(Config::KEY_THEME_NAME);
155
        $engineName = get_config()->getString(Config::KEY_TPL_ENGINE);
156
157
        switch ($engineName) {
158
            case 'twig':
159
                $engine = build_twig_template_engine($themeName);
160
                break;
161
            case 'smarty':
162
            case 'php':
163
                throw new InternalException("Implement template engine [$engineName]");
164
            default:
165
                throw new \InvalidArgumentException("Unsupported template engine [$engineName]");
166
        }
167
    }
168
    return $engine;
169
}
170
171
/**
172
 * Build the twig template engine.
173
 * @param string $themeName The name of the configure theme
174
 * @return TemplateEngine
175
 */
176
function build_twig_template_engine(string $themeName): TemplateEngine {
177
    $caching = false;
178
    if (get_config()->getBool(Config::KEY_TPL_CACHING)) {
179
        $caching = TEMPLATE_CACHE_ROOT;
180
    }
181
    $strict = get_config()->getBool(Config::KEY_TPL_STRICT_VARS_TWIG);
182
    $options = [
183
        'cache' => $caching,
184
        'strict_variables' => $strict
185
    ];
186
    $templateDirs = [THEMES_ROOT.DS.'twig'.DS.$themeName];
187
    return new TwigTemplateEngine($templateDirs, $options);
188
}
189
190
/**
191
 * Returns the instance of the <code>IndexManager</code>.
192
 * @return IndexManager
193
 */
194
function get_index_manager(): IndexManager {
195
    static $manager = null;
196
    if ($manager === null) {
197
        $manager = new IndexManager(APP_ROOT);
198
    }
199
    return $manager;
200
}
201
202
/**
203
 * Return the instance of the <code>Config</code>.
204
 * @return Config
205
 */
206
function get_config(): Config {
207
    static $config = null;
208
    if (empty($config)) {
209
        $config = new Config(CONFIG_ROOT);
210
    }
211
    return $config;
212
}
213
214
/**
215
 * Returns the instance of the <code>ModelFactory</code>.
216
 * @return ModelFactory
217
 */
218
function get_model_factory(): ModelFactory {
219
    static $factory = null;
220
    if (empty($factory)) {
221
        $factory = new ModelFactory(get_config(), get_markdown_parser(), get_index_manager());
222
    }
223
    return $factory;
224
}
225
226
/**
227
 * Returns the instance of the <code>MarkdownParser</code>.
228
 * @return MarkdownParser
229
 */
230
function get_markdown_parser(): MarkdownParser {
231
    static $parser = null;
232
    if (empty($parser)) {
233
        $parser = new ParsedownParser();
234
    }
235
    return $parser;
236
}
237
238
/**
239
 * Get a <code>Content</code> object (if any) associated with the given slug.
240
 * @param string $slug
241
 * @param array<\stdClass> $list List of <code>Content</code> for this <code>Content</code> object.
242
 * @param string $template
243
 * @return \stdClass|NULL if no content was found associated with the given slug <code>null</code> is returned.
244
 */
245
function get_content_object(string $slug, array $list = [], string $template = DEFAULT_TEMPLATE): ?\stdClass {
246
    $manager = get_index_manager();
247
    if ($manager->elementExists($slug) === false) {
248
        return null;
249
    }
250
    $content = get_model_factory()->createContentObject($manager->getElementFromSlugIndex($slug));
251
    if (empty($list) === false) {
252
        $content->list = $list;
253
    }
254
    $content->menus = get_menus();
255
    if ($content !== null && empty($content->template)) {
256
        $content->template = $template;
257
    }
258
    return $content;
259
}
260
261
/**
262
 * Returns a pagination page of posts.
263
 * @param int $pageNum The page number
264
 * @param int $perPage Items per page
265
 * @return array<\stdClass> The resulting list of posts
266
 */
267
function get_posts(int $pageNum = 1, int $perPage = 5): array {
268
    $posts = get_index_manager()->getPostsIndex();
269
    $posts = \array_slice($posts, ($pageNum - 1) * $perPage, $perPage);
270
    $list = [];
271
    $factory = get_model_factory();
272
    foreach ($posts as $post) {
273
        $list[] = $factory->createContentObject($post);
274
    }
275
    return $list;
276
}
277
278
/**
279
 * Checks if the given slug exists in the index manager (alias for <code>IndexManager::elementExists()</code>).
280
 * @param string $slug
281
 * @return bool
282
 */
283
function slug_exists(string $slug): bool {
284
    return get_index_manager()->elementExists($slug);
285
}
286
287
/**
288
 * Returns a list of widgets
289
 * @return array<mixed>
290
 */
291
function get_widgets(): array {
292
    return [
293
        'recent_posts' => get_posts(),
294
        'category_list' => get_categories(),
295
        'tag_list' => get_tags()
296
    ];
297
}
298
299
/**
300
 * Returns an array of post objects for the given section URI.
301
 * @param string $section
302
 * @param string $uri
303
 * @param int $pageNum
304
 * @param int $perPage
305
 * @throws InternalException
306
 * @throws \InvalidArgumentException
307
 * @return array<\stdClass>
308
 */
309
function get_posts_for_section(string $section, string $uri, int $pageNum = 1, int $perPage = 5): array {
310
    $manager = get_index_manager();
311
    if ($manager->elementExists($uri) === false) {
312
        throw new InternalException("Element does not exist [$uri]");
313
    }
314
315
    switch ($section) {
316
        case CATEGORY_SECTION:
317
            $posts = $manager->getPostsForCategoryIndex()[$uri];
318
            break;
319
        case TAG_SECTION:
320
            $posts = $manager->getPostsForTagIndex()[$uri];
321
            break;
322
        default:
323
            throw new \InvalidArgumentException("Unsupported section [$section]");
324
    }
325
326
    $posts = \array_slice($posts, ($pageNum - 1) * $perPage, $perPage);
327
    return get_model_list_from_uris($posts);
328
}
329