Passed
Push — develop ( bcf814...d07230 )
by Schlaefer
02:57
created

Page::getPage()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 12
cts 12
cp 1
rs 9.2
c 0
b 0
f 0
cc 4
eloc 13
nc 6
nop 2
crap 4
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 20
    public function __construct($settings = null)
40
    {
41 20
        if ($settings === null) {
42 20
            $settings = Container::getInstance()->get('Phile_Config')->toArray();
43
        }
44 20
        $this->settings = $settings;
45 20
        $this->cache = ServiceLocator::getService('Phile_Cache');
46 20
    }
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 18
    public function findByPath($pageId, $folder = null)
57
    {
58 18
        $folder = $folder ?: $this->settings['content_dir'];
59
        // be merciful to lazy third-party-usage and accept a leading slash
60 18
        $pageId = ltrim($pageId, '/');
61
        // 'sub/' should serve page 'sub/index'
62 18
        if ($pageId === '' || substr($pageId, -1) === '/') {
63 10
            $pageId .= 'index';
64
        }
65
66 18
        $file = $folder . $pageId . $this->settings['content_ext'];
67 18
        if (!file_exists($file)) {
68 5
            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 5
                $pageId .= '/index';
74
            }
75 5
            $file = $folder . $pageId . $this->settings['content_ext'];
76
        }
77 18
        if (!file_exists($file)) {
78 4
            return null;
79
        }
80 17
        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 6
    public function findAll(array $options = array(), $folder = null)
92
    {
93 6
        $folder = $folder ?: $this->settings['content_dir'];
94 6
        return new PageCollection(
95 6
            function () use ($options, $folder) {
96 6
                $options += $this->settings;
97
                // ignore files with a leading '.' in its filename
98 6
                $files = Utility::getFiles($folder, '\Phile\FilterIterator\ContentFileFilterIterator');
99 6
                $pages = array();
100 6
                $notFoundPage = $this->settings['not_found_page'] . $this->settings['content_ext'];
101 6
                foreach ($files as $file) {
102 6
                    if (str_replace($folder, '', $file) == $notFoundPage) {
103
                        // jump to next page if file is the 404 page
104 6
                        continue;
105
                    }
106 6
                    $pages[] = $this->getPage($file, $folder);
107
                }
108
109 6
                if (empty($options['pages_order'])) {
110
                    return $pages;
111
                }
112
113
                // parse search criteria
114 6
                $terms = preg_split('/\s+/', $options['pages_order'], -1, PREG_SPLIT_NO_EMPTY);
115 6
                foreach ($terms as $term) {
116 6
                    $sub = explode('.', $term);
117 6
                    if (count($sub) > 1) {
118 5
                        $type = array_shift($sub);
119
                    } else {
120 1
                        $type = null;
121
                    }
122 6
                    $sub = explode(':', $sub[0]);
123 6
                    if (count($sub) === 1) {
124 1
                        $sub[1] = 'asc';
125
                    }
126 6
                    $sorting[] = array('type' => $type, 'key' => $sub[0], 'order' => $sub[1], 'string' => $term);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$sorting was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sorting = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
127
                }
128
129
                // prepare search criteria for array_multisort
130 6
                foreach ($sorting as $sort) {
0 ignored issues
show
Bug introduced by
The variable $sorting does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
131 6
                    $key = $sort['key'];
132 6
                    $column = array();
133 6
                    foreach ($pages as $page) {
134
                        /**
135
                         * @var \Phile\Model\Page $page
136
                         */
137 6
                        $meta = $page->getMeta();
138 6
                        if ($sort['type'] === 'page') {
139
                            $method = 'get' . ucfirst($key);
140
                            $value = $page->$method();
141 6
                        } elseif ($sort['type'] === 'meta') {
142 5
                            $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 5
                        $column[] = $value;
151
                    }
152 5
                    $sortHelper[] = $column;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$sortHelper was never initialized. Although not strictly required by PHP, it is generally a good practice to add $sortHelper = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
153 5
                    $sortHelper[] = constant('SORT_' . strtoupper($sort['order']));
154
                }
155 5
                $sortHelper[] = &$pages;
0 ignored issues
show
Bug introduced by
The variable $sortHelper does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
156
157 5
                call_user_func_array('array_multisort', $sortHelper);
158
159 5
                return $pages;
160 6
            }
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 19
    protected function getPage(string $filePath, ?string $folder = null): \Phile\Model\Page
194
    {
195 19
        $folder = $folder ?: $this->settings['content_dir'];
196 19
        $key = 'Phile_Model_Page_' . md5($filePath);
197 19
        if (isset($this->storage[$key])) {
198 5
            return $this->storage[$key];
199
        }
200
201 19
        if ($this->cache->has($key)) {
202 1
            $page = $this->cache->get($key);
203
        } else {
204 19
            $page = new \Phile\Model\Page($filePath, $folder);
205 19
            $this->cache->set($key, $page);
206
        }
207 19
        $page->setRepository($this);
208 19
        $this->storage[$key] = $page;
209
210 19
        return $page;
211
    }
212
}
213