Create::process()   C
last analyzed

Complexity

Conditions 15
Paths 8

Size

Total Lines 91
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 39
CRAP Score 15.3298

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 15
eloc 43
c 1
b 1
f 0
nc 8
nop 0
dl 0
loc 91
ccs 39
cts 44
cp 0.8864
crap 15.3298
rs 5.9166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Cecil\Step\Menus;
15
16
use Cecil\Collection\Menu\Collection as MenusCollection;
17
use Cecil\Collection\Menu\Entry;
18
use Cecil\Collection\Menu\Menu;
19
use Cecil\Collection\Page\Page;
20
use Cecil\Exception\RuntimeException;
21
use Cecil\Logger\PrintLogger;
22
use Cecil\Renderer\Page as PageRenderer;
23
use Cecil\Step\AbstractStep;
24
25
/**
26
 * Create menus step.
27
 *
28
 * This step is responsible for creating menus based on the configuration
29
 * and the pages defined in the site. It initializes a collection of menus
30
 * for each language, adds a default "main" menu, and processes the configuration
31
 * to add, remove, or replace menu entries. It also creates menus from pages
32
 * that have a `menu` variable defined, allowing for dynamic menu generation
33
 * based on the content of the site.
34
 */
35
class Create extends AbstractStep
36
{
37
    /** @var array */
38
    protected $menus;
39
40
    /**
41
     * {@inheritdoc}
42
     */
43 1
    public function getName(): string
44
    {
45 1
        return 'Creating menus';
46
    }
47
48
    /**
49
     * {@inheritdoc}
50
     *
51
     * @throws RuntimeException
52
     */
53 1
    public function process(): void
54
    {
55
        // creates a Menu collection for each language, with a default "main" menu
56 1
        foreach ($this->config->getLanguages() as $language) {
57 1
            $this->menus[$language['code']] = new MenusCollection('menus');
58 1
            $this->menus[$language['code']]->add(new Menu('main'));
59
        }
60
61 1
        $this->createMenusFromPages();
62
63
        /**
64
         * Removing/adding/replacing menus entries from config.
65
         * ie:
66
         *   menus:
67
         *     main:
68
         *       # remove
69
         *       - id: about
70
         *         enabled: false
71
         *       # add
72
         *       - id: example
73
         *         name: "Example"
74
         *         url: https://example.com
75
         *         weight: 999
76
         *       # replace
77
         *       - id: index
78
         *         name: "Home page"
79
         */
80 1
        foreach ($this->config->getLanguages() as $language) {
81 1
            if ($menusConfig = (array) $this->config->get('menus', $language['code'], false)) {
82 1
                $totalConfig = array_sum(array_map('count', $menusConfig));
83 1
                $countConfig = 0;
84
85 1
                foreach ($menusConfig as $menuConfig => $entry) {
86 1
                    if (!\is_array($entry)) {
87
                        break;
88
                    }
89
                    // add Menu if not exists
90 1
                    if (!$this->menus[$language['code']]->has($menuConfig)) {
91
                        $this->menus[$language['code']]->add(new Menu($menuConfig));
92
                    }
93
                    /** @var \Cecil\Collection\Menu\Menu $menu */
94 1
                    $menu = $this->menus[$language['code']]->get($menuConfig);
95 1
                    foreach ($entry as $key => $properties) {
96 1
                        $countConfig++;
97 1
                        $updated = false;
98
99
                        // ID is required
100 1
                        if (!isset($properties['id'])) {
101
                            $this->builder->getLogger()->error(\sprintf('Config menu entry: key "id" is required for entry at position %s in "%s" menu', $key, $menu), ['progress' => [$countConfig, $totalConfig]]);
102
                            continue;
103
                        }
104
                        /** @var \Cecil\Collection\Menu\Entry $item */
105 1
                        $item = (new Entry($properties['id']))
106 1
                            ->setName($properties['name'] ?? ucfirst($properties['id']))
107 1
                            ->setUrl($properties['url'] ?? '404')
108 1
                            ->setWeight((int) ($properties['weight'] ?? 0));
109
                        // is entry already exists?
110 1
                        if ($menu->has($properties['id'])) {
111
                            // removes a not enabled entry
112 1
                            if (isset($properties['enabled']) && $properties['enabled'] === false) {
113 1
                                $menu->remove($properties['id']);
114
115 1
                                $message = \sprintf('Config menu entry "%s (%s) > %s" removed', (string) $menu, $language['code'], $properties['id']);
116 1
                                $this->builder->getLogger()->info($message, ['progress' => [$countConfig, $totalConfig]]);
117 1
                                continue;
118
                            }
119
                            // merges properties
120 1
                            $current = $menu->get($properties['id'])->toArray();
121 1
                            $properties = array_merge($current, $properties);
122
                            /** @var \Cecil\Collection\Menu\Entry $item */
123 1
                            $item = clone $menu->get($properties['id']);
124 1
                            $item->setName($properties['name'])
125 1
                                ->setUrl($properties['url'])
126 1
                                ->setWeight($properties['weight']);
127 1
                            $updated = true;
128
                        }
129
                        // abord if entry is not enabled
130 1
                        if (isset($properties['enabled']) && $properties['enabled'] === false) {
131
                            continue;
132
                        }
133
                        // adds/replaces entry
134 1
                        $menu->add($item);
135
136 1
                        $message = \sprintf('Config menu entry "%s (%s) > %s" %s {name: %s, url: %s, weight: %s}', (string) $menu, $language['code'], $item->getId(), $updated ? 'updated' : 'created', $item-> getName(), $item->getUrl(), $item->getWeight());
137 1
                        $this->builder->getLogger()->info($message, ['progress' => [$countConfig, $totalConfig]]);
138
                    }
139
                }
140
            }
141
        }
142
143 1
        $this->builder->setMenus($this->menus);
144
    }
145
146
    /**
147
     * Create menus from pages' `menu` variable.
148
     */
149 1
    protected function createMenusFromPages(): void
150
    {
151 1
        $filteredPages = $this->builder->getPages()->filter(function (Page $page) {
152 1
            return $page->hasVariable('menu')
153 1
                && $page->getVariable('published') === true
154 1
                && \in_array($page->getVariable('language', $this->config->getLanguageDefault()), array_column($this->config->getLanguages(), 'code'));
155 1
        });
156
157 1
        $total = \count($filteredPages);
158 1
        $count = 0;
159
        /** @var \Cecil\Collection\Page\Page $page */
160 1
        foreach ($filteredPages as $page) {
161 1
            $count++;
162 1
            $language = $page->getVariable('language', $this->config->getLanguageDefault());
163
            /**
164
             * Array case.
165
             *
166
             * case 1:
167
             *   menu: [main, navigation]
168
             * case 2:
169
             *   menu:
170
             *     main:
171
             *       weight: 999
172
             */
173 1
            if (\is_array($page->getVariable('menu'))) {
174 1
                foreach ($page->getVariable('menu') as $key => $value) {
175 1
                    $menuName = $key;
176 1
                    $properties = $value;
177 1
                    if (\is_int($key)) {
178 1
                        $menuName = $value;
179 1
                        $properties = null;
180
                    }
181 1
                    if (!\is_string($menuName)) {
182
                        $this->builder->getLogger()->error(\sprintf('Menu\'s name of page "%s" must be a string, not "%s"', $page->getId(), PrintLogger::format($menuName)), ['progress' => [$count, $total]]);
183
                        continue;
184
                    }
185 1
                    $item = (new Entry($page->getIdWithoutLang()))
186 1
                        ->setName($page->getVariable('title'))
187 1
                        ->setUrl((new PageRenderer($this->builder, $page))->getPath());
188 1
                    if (isset($properties['weight'])) {
189 1
                        $item->setWeight((int) $properties['weight']);
190
                    }
191
                    // add Menu if not exists
192 1
                    if (!$this->menus[$language]->has($menuName)) {
193 1
                        $this->menus[$language]->add(new Menu($menuName));
194
                    }
195
                    /** @var \Cecil\Collection\Menu\Menu $menu */
196 1
                    $menu = $this->menus[$language]->get($menuName);
197 1
                    $menu->add($item);
198
199 1
                    $message = \sprintf('Page menu entry "%s (%s) > %s" created {name: %s, weight: %s}', $menu->getId(), $language, $item->getId(), $item->getName(), $properties['weight'] ?? 'N/A');
200 1
                    $this->builder->getLogger()->info($message, ['progress' => [$count, $total]]);
201
                }
202 1
                continue;
203
            }
204
            /**
205
             * String case.
206
             *
207
             * e.g.:
208
             *   menu: main
209
             */
210 1
            $item = (new Entry($page->getIdWithoutLang()))
211 1
                ->setName($page->getVariable('title'))
212 1
                ->setUrl((new PageRenderer($this->builder, $page))->getPath());
213
            // add Menu if not exists
214 1
            if (!$this->menus[$language]->has($page->getVariable('menu'))) {
215
                $this->menus[$language]->add(new Menu($page->getVariable('menu')));
216
            }
217
            /** @var \Cecil\Collection\Menu\Menu $menu */
218 1
            $menu = $this->menus[$language]->get($page->getVariable('menu'));
219 1
            $menu->add($item);
220
221 1
            $message = \sprintf('Page menu entry "%s (%s) > %s" created {name: %s}', $menu->getId(), $language, $item->getId(), $item->getName());
222 1
            $this->builder->getLogger()->info($message, ['progress' => [$count, $total]]);
223
        }
224
    }
225
}
226