Passed
Branch master (748c89)
by Schlaefer
02:28
created

Page::getPage()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 18
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

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