Passed
Push — master ( 183e2b...3b90aa )
by Mikael
02:22
created

src/Content/FBCLoadAdditionalContentTrait.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Anax\Content;
4
5
/**
6
 * File Based Content, code for loading additional content into view through
7
 * data["meta"].
8
 */
9
trait FBCLoadAdditionalContentTrait
10
{
11
    /**
12
     * Load extra info into views based of meta information provided in each
13
     * view.
14
     *
15
     * @param array  &$views     with all views.
16
     * @param string $route      current route
17
     * @param string $routeIndex route with appended /index
18
     *
19
     * @throws NotFoundException when mapping can not be done.
20
     *
21
     * @return void.
22
     */
23
    private function loadAdditionalContent(&$views, $route, $routeIndex)
24
    {
25
        foreach ($views as $id => $view) {
26
            $meta = isset($view["data"]["meta"])
27
                ? $view["data"]["meta"]
28
                : null;
29
30
            if (is_array($meta)) {
31
                switch ($meta["type"]) {
32
                    case "article-toc":
33
                        $content = $views["main"]["data"]["content"];
34
                        $views[$id]["data"]["articleToc"] = $this->di->get("textfilter")->createToc($content);
35
                        break;
36
37
                    case "breadcrumb":
38
                        $views[$id]["data"]["breadcrumb"] = $this->createBreadcrumb($route);
39
                        break;
40
41
                    case "next-previous":
42
                        $baseRoute = dirname($routeIndex);
43
                        $this->orderToc($baseRoute, $meta);
44
                        list($next, $previous) = $this->findNextAndPrevious($routeIndex);
45
                        $views[$id]["data"]["next"] = $next;
46
                        $views[$id]["data"]["previous"] = $previous;
47
                        break;
48
49
                    case "single": // OBSOLETE
50
                    case "content":
51
                        $route = $this->getActiveRoute($meta["route"], $routeIndex);
52
53
                        // Load and parse route as view. Load meta view
54
                        // if any.
55
                        // Current view details preceds the loaded once.
56
                        $view = $this->loadAndParseRoute($route);
57
                        $views[$id] = array_merge_recursive_distinct($view, $views[$id]);
58
                        break;
59
60
                    case "columns":
61
                        // Each column is an own view set with details
62
                        // Process as meta view and load additional content
63
                        $template = isset($meta["template"])
64
                            ? $meta["template"]
65
                            : null;
66
                        $columns = $meta["columns"];
67
                        foreach ($columns as $key => $view) {
68
                            $views2 = [ "main" => $view ];
69
                            $this->loadAdditionalContent($views2, $route, $routeIndex);
70
                            $columns[$key] = $views2["main"];
71
                            
72
                            if ($template) {
73
                                $columns[$key]["template"] = $template;
74
                            }
75
                        }
76
                        $views[$id]["data"]["columns"] = $columns;
77
                        break;
78
79
                    case "toc-sort":
80
                        $baseRoute = dirname($routeIndex);
81
                        $this->orderToc($baseRoute, $meta);
82
                        break;
83
84
                    case "toc":
85
                        $baseRoute = dirname($routeIndex);
86
87
                        // Include support for ordering
88
                        if (isset($meta["orderby"])
89
                            || isset($meta["orderorder"])) {
90
                            $this->orderToc($baseRoute, $meta);
91
                        }
92
93
                        // Same as toc-route
94
                        $toc = $this->meta[$baseRoute]["__toc__"];
95
                        $this->limitToc($toc, $meta);
96
                        $views[$id]["data"]["toc"] = $toc;
97
                        $views[$id]["data"]["meta"] = $meta;
98
                        break;
99
100
                    case "toc-route":
101
                        // Get the toc for a specific route
102
                        $route = $this->getActiveRoute($meta["route"], $routeIndex);
103
                        $routeIndex2 = $this->mapRoute2IndexKey($route);
104
                        $baseRoute = dirname($routeIndex2);
105
106
                        // Include support for ordering
107
                        if (isset($meta["orderby"])
108
                            || isset($meta["orderorder"])) {
109
                            $this->orderToc($baseRoute, $meta);
0 ignored issues
show
$meta is of type array<string,?,{"type":"?","orderby":"?"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
110
                        }
111
112
                        // Same as toc
113
                        $toc = $this->meta[$baseRoute]["__toc__"];
114
                        $this->limitToc($toc, $meta, $baseRoute);
115
                        $views[$id]["data"]["toc"] = $toc;
116
                        $views[$id]["data"]["meta"] = $meta;
117
                        break;
118
119
                    case "book-toc":
120
                        $toc = $this->meta[$baseRoute]["__toc__"];
121
                        $views[$id]["data"]["toc"] = $toc;
122
                        break;
123
124
                    case "author":
125
                        if (isset($views["main"]["data"]["author"])) {
126
                            $views[$id]["data"]["author"] = $this->loadAuthorDetails($views["main"]["data"]["author"]);
127
                        }
128
                        break;
129
130
                    case "copy":
131
                        $viewToCopy = $views[$id]["data"]["meta"]["view"];
132
                        $views[$id]["data"] = array_merge_recursive_distinct(
133
                            $views[$viewToCopy]["data"],
134
                            $views[$id]["data"]
135
                        );
136
                        break;
137
138
                    default:
139
                        $msg = t("Unsupported data/meta/type '!TYPE' for additional content.", [
140
                            "!TYPE" => $meta["type"]
141
                        ]);
142
                        throw new Exception($msg);
143
                }
144
            }
145
        }
146
    }
147
148
149
150
    /**
151
     * Find next and previous links of current content.
152
     *
153
     * @param string $routeIndex target route to find next and previous for.
154
     *
155
     * @return array with next and previous if found.
156
     */
157
    private function findNextAndPrevious($routeIndex)
158
    {
159
        $key = dirname($routeIndex);
160
        if (!isset($this->meta[$key]["__toc__"])) {
161
            return [null, null];
162
        }
163
164
        $toc = $this->meta[$key]["__toc__"];
165
        if (!isset($toc[$routeIndex])) {
166
            return [null, null];
167
        }
168
169
        $index2Key = array_keys($toc);
170
        $keys = array_flip($index2Key);
171
        $values = array_values($toc);
172
        $count = count($keys);
173
174
        $current = $keys[$routeIndex];
175
        $previous = null;
176 View Code Duplication
        for ($i = $current - 1; $i >= 0; $i--) {
177
            $isSectionHeader = $values[$i]["sectionHeader"];
178
            $isLinkable = $values[$i]["linkable"]; // ?? null;
179
            $isInternal = $values[$i]["internal"];
180
            if (($isSectionHeader && !$isLinkable) || $isInternal) {
181
                continue;
182
            }
183
            $previous = $values[$i];
184
            $previous["route"] = $index2Key[$i];
185
            break;
186
        }
187
        
188
        $next = null;
189 View Code Duplication
        for ($i = $current + 1; $i < $count; $i++) {
190
            $isSectionHeader = $values[$i]["sectionHeader"];
191
            $isLinkable = $values[$i]["linkable"]; // ?? null;
192
            $isInternal = $values[$i]["internal"];
193
            if (($isSectionHeader && !$isLinkable) || $isInternal) {
194
                continue;
195
            }
196
            $next = $values[$i];
197
            $next["route"] = $index2Key[$i];
198
            break;
199
        }
200
201
        return [$next, $previous];
202
    }
203
204
205
206
    /**
207
     * Order toc items.
208
     *
209
     * @param string $baseRoute route to use to find __toc__.
210
     * @param string $meta on how to order toc.
211
     *
212
     * @return void.
213
     */
214
    private function orderToc($baseRoute, $meta)
215
    {
216
        $defaults = [
217
            "orderby" => "section",
218
            "orderorder" => "asc",
219
        ];
220
        $options = array_merge($defaults, $meta);
221
        $orderby = $options["orderby"];
222
        $order   = $options["orderorder"];
223
        $toc = $this->meta[$baseRoute]["__toc__"];
224
225
        uksort($toc, function ($a, $b) use ($toc, $orderby, $order) {
226
                $a = $toc[$a][$orderby];
227
                $b = $toc[$b][$orderby];
228
229
                $asc = $order == "asc" ? 1 : -1;
230
                
231
            if ($a == $b) {
232
                return 0;
233
            } elseif ($a > $b) {
234
                return $asc;
235
            }
236
                return -$asc;
237
        });
238
239
        $this->meta[$baseRoute]["__toc__"] = $toc;
240
    }
241
242
243
    /**
244
     * Limit and paginate toc items.
245
     *
246
     * @param string &$toc      array with current toc.
247
     * @param string &$meta     on how to order and limit toc.
248
     * @param string $baseRoute prepend to next & previous urls.
249
     *
250
     * @return void.
251
     */
252
    private function limitToc(&$toc, &$meta, $baseRoute = null)
253
    {
254
        $defaults = [
255
            "items" => 7,
256
            "offset" => 0,
257
        ];
258
        $options = array_merge($defaults, $meta);
259
260
        // Check if pagination is currently used
261
        if ($this->currentPage) {
262
            $options["offset"] = ($this->currentPage - 1) * $options["items"];
263
        }
264
265
        $meta["totalItems"] = count($toc);
266
        $meta["currentPage"] = (int) floor($options["offset"] / $options["items"]) + 1;
267
        $meta["totalPages"] = (int) floor($meta["totalItems"] / $options["items"] + 1);
268
269
        // Next and previous page
270
        $pagination = $this->config["pagination"];
271
        $meta["nextPageUrl"] = null;
272
        $meta["previousPageUrl"] = null;
273
        $baseRoute = isset($baseRoute)
274
            ? $baseRoute
275
            : $this->baseRoute;
276
277
        if ($meta["currentPage"] > 1 && $meta["totalPages"] > 1) {
278
            $previousPage = $meta["currentPage"] - 1;
279
            $previous = "";
280
            if ($previousPage != 1) {
281
                $previous = "$pagination/$previousPage";
282
            }
283
            $meta["previousPageUrl"] = "$baseRoute/$previous";
284
        }
285
286
        if ($meta["currentPage"] < $meta["totalPages"]) {
287
            $nextPage = $meta["currentPage"] + 1;
288
            $meta["nextPageUrl"] = "$baseRoute/$pagination/$nextPage";
289
        }
290
291
292
        // Only use slice of toc
293
        $startSlice = ($meta["currentPage"] - 1) * $options["items"];
294
        $toc = array_slice($toc, $startSlice, $options["items"]);
295
        $meta["displayedItems"] = count($toc);
296
    }
297
}
298