Page::findByPath()   B
last analyzed

Complexity

Conditions 7
Paths 12

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 7
eloc 14
c 5
b 0
f 0
nc 12
nop 2
dl 0
loc 25
ccs 14
cts 14
cp 1
crap 7
rs 8.8333
1
<?php
2
/**
3
 * the page repository class
4
 */
5
namespace Phile\Repository;
6
7
use Phile\Core\Container;
8
use Phile\Core\ServiceLocator;
9
use Phile\Core\Utility;
10
use Phile\ServiceLocator\CacheInterface;
11
12
/**
13
 * the Repository class for pages
14
 *
15
 * @author  Frank Nägler
16
 * @link    https://philecms.github.io
17
 * @license http://opensource.org/licenses/MIT
18
 * @package Phile\Repository
19
 */
20
class Page
21
{
22
    /**
23
     * @var array the settings array
24
     */
25
    protected $settings;
26
27
    /**
28
     * @var array object storage for initialized objects, to prevent multiple loading of objects.
29
     */
30
    protected $storage = [];
31
32
    /**
33
     * @var CacheInterface the cache implementation
34
     */
35
    protected $cache;
36
37
    /**
38
     * the constructor
39
     */
40 23
    public function __construct(?array $settings = null)
41
    {
42 23
        if ($settings === null) {
43 23
            $settings = Container::getInstance()->get('Phile_Config')->toArray();
44
        }
45 23
        $this->settings = $settings;
46 23
        $this->cache = ServiceLocator::getService('Phile_Cache');
47
    }
48
49
    /**
50
     * find a page by path
51
     *
52
     * @param string $pageId
53
     * @param string $folder
54
     *
55
     * @return null|\Phile\Model\Page
56
     */
57 21
    public function findByPath($pageId, $folder = null)
58
    {
59 21
        $folder = $folder ?: $this->settings['content_dir'];
60
        // be merciful to lazy third-party-usage and accept a leading slash
61 21
        $pageId = ltrim($pageId, '/');
62
        // 'sub/' should serve page 'sub/index'
63 21
        if ($pageId === '' || substr($pageId, -1) === '/') {
64 10
            $pageId .= 'index';
65
        }
66
67 21
        $file = $folder . $pageId . $this->settings['content_ext'];
68 21
        if (!file_exists($file)) {
69 8
            if (substr($pageId, -6) === '/index') {
70
                // try to resolve sub-directory 'sub/' to page 'sub'
71 1
                $pageId = substr($pageId, 0, strlen($pageId) - 6);
72
            } else {
73
                // try to resolve page 'sub' to sub-directory 'sub/'
74 8
                $pageId .= '/index';
75
            }
76 8
            $file = $folder . $pageId . $this->settings['content_ext'];
77
        }
78 21
        if (!file_exists($file)) {
79 7
            return null;
80
        }
81 20
        return $this->getPage($file, $folder);
82
    }
83
84
    /**
85
     * find all pages (*.md) files and returns an array of Page models
86
     *
87
     * @param array  $options
88
     * @param string $folder
89
     *
90
     * @return PageCollection of \Phile\Model\Page objects
91
     */
92 9
    public function findAll(array $options = array(), $folder = null)
93
    {
94 9
        $folder = $folder ?: $this->settings['content_dir'];
95 9
        return new PageCollection(
96 9
            function () use ($options, $folder): array {
97 9
                $options += $this->settings;
98
                // ignore files with a leading '.' in its filename
99 9
                $files = Utility::getFiles($folder, '\Phile\FilterIterator\ContentFileFilterIterator');
100 9
                $pages = [];
101 9
                $notFoundPage = $this->settings['not_found_page'] . $this->settings['content_ext'];
102 9
                foreach ($files as $file) {
103 9
                    if (str_replace($folder, '', $file) == $notFoundPage) {
104
                        // jump to next page if file is the 404 page
105 9
                        continue;
106
                    }
107 9
                    $pages[] = $this->getPage($file, $folder);
108
                }
109
110 9
                if (empty($options['pages_order'])) {
111
                    return $pages;
112
                }
113
114
                // parse search criteria
115 9
                $sorting = [];
116 9
                $terms = preg_split('/\s+/', $options['pages_order'], -1, PREG_SPLIT_NO_EMPTY);
117 9
                foreach ($terms as $term) {
118 9
                    $sub = explode('.', $term);
119 9
                    if (count($sub) > 1) {
120 8
                        $type = array_shift($sub);
121
                    } else {
122 1
                        $type = null;
123
                    }
124 9
                    $sub = explode(':', $sub[0]);
125 9
                    if (count($sub) === 1) {
126 1
                        $sub[1] = 'asc';
127
                    }
128 9
                    $sorting[] = array('type' => $type, 'key' => $sub[0], 'order' => $sub[1], 'string' => $term);
129
                }
130
131 9
                if (empty($sorting)) {
132
                    return $pages;
133
                }
134
135
                // prepare search criteria for array_multisort
136 9
                $sortHelper = [];
137 9
                foreach ($sorting as $sort) {
138 9
                    $key = $sort['key'];
139 9
                    $column = array();
140 9
                    foreach ($pages as $page) {
141
                        /**
142
                         * @var \Phile\Model\Page $page
143
                         */
144 9
                        $meta = $page->getMeta();
145 9
                        if ($sort['type'] === 'page') {
146
                            $method = 'get' . ucfirst($key);
147
                            $value = $page->$method();
148 9
                        } elseif ($sort['type'] === 'meta') {
149 8
                            $value = $meta->get($key);
150
                        } else {
151 1
                            trigger_error(
152 1
                                "Page order '{$sort['string']}' was ignored. Type '{$sort['type']}' not recognized.",
153
                                E_USER_WARNING
154
                            );
155
                            continue 2;
156
                        }
157 8
                        $column[] = $value;
158
                    }
159 8
                    $sortHelper[] = $column;
160 8
                    $sortHelper[] = constant('SORT_' . strtoupper($sort['order']));
161
                }
162 8
                $sortHelper[] = &$pages;
163
164 8
                call_user_func_array('array_multisort', $sortHelper);
165
166 8
                return $pages;
167
            }
168
        );
169
    }
170
171
    /**
172
     * return page at offset from $page in applied search order
173
     *
174
     * @param  \Phile\Model\Page $page
175
     * @param  int               $offset
176
     * @return null|\Phile\Model\Page
177
     */
178 2
    public function getPageOffset(\Phile\Model\Page $page, $offset = 0)
179
    {
180 2
        $pages = $this->findAll();
181 2
        $order = array();
182 2
        foreach ($pages as $p) {
183 2
            $order[] = $p->getFilePath();
184
        }
185 2
        $key = array_search($page->getFilePath(), $order) + $offset;
186 2
        if (!isset($order[$key])) {
187
            return null;
188
        }
189 2
        return $this->getPage($order[$key]);
190
    }
191
192
    /**
193
     * get page from cache or filepath
194
     *
195
     * @param string $filePath
196
     * @param string|null $folder
197
     *
198
     * @return \Phile\Model\Page
199
     */
200 22
    protected function getPage(string $filePath, ?string $folder = null): \Phile\Model\Page
201
    {
202 22
        $folder = $folder ?: $this->settings['content_dir'];
203 22
        $key = 'Phile_Model_Page_' . md5($filePath);
204 22
        if (isset($this->storage[$key])) {
205 5
            return $this->storage[$key];
206
        }
207
208 22
        if ($this->cache->has($key)) {
209 1
            $page = $this->cache->get($key);
210
        } else {
211 22
            $page = new \Phile\Model\Page($filePath, $folder);
212 22
            $this->cache->set($key, $page);
213
        }
214 22
        $page->setRepository($this);
215 22
        $this->storage[$key] = $page;
216
217 22
        return $page;
218
    }
219
}
220