Passed
Push — develop ( e37a4b...d665c0 )
by Schlaefer
38s
created

Page::findByPath()   C

Complexity

Conditions 7
Paths 24

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 14
cts 14
cp 1
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 15
nc 24
nop 2
crap 7
1
<?php
2
/**
3
 * the page repository class
4
 */
5
namespace Phile\Repository;
6
7
use Phile\Core\Registry;
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 16
    public function __construct($settings = null)
40
    {
41 16
        if ($settings === null) {
42 16
            $settings = Registry::get('Phile_Settings');
43
        }
44 16
        $this->settings = $settings;
0 ignored issues
show
Documentation Bug introduced by
It seems like $settings of type * is incompatible with the declared type array of property $settings.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
45 16
        if (ServiceLocator::hasService('Phile_Cache')) {
46
            $this->cache = ServiceLocator::getService('Phile_Cache');
47
        }
48 16
    }
49
50
    /**
51
     * find a page by path
52
     *
53
     * @param string $pageId
54
     * @param string $folder
55
     *
56
     * @return null|\Phile\Model\Page
57
     */
58 14
    public function findByPath($pageId, $folder = null)
59
    {
60 14
        $folder = $folder ?: $this->settings['content_dir'];
61
        // be merciful to lazy third-party-usage and accept a leading slash
62 14
        $pageId = ltrim($pageId, '/');
63
        // 'sub/' should serve page 'sub/index'
64 14
        if ($pageId === '' || substr($pageId, -1) === '/') {
65 10
            $pageId .= 'index';
66
        }
67
68 14
        $file = $folder . $pageId . $this->settings['content_ext'];
69 14
        if (!file_exists($file)) {
70 3
            if (substr($pageId, -6) === '/index') {
71
                // try to resolve sub-directory 'sub/' to page 'sub'
72 1
                $pageId = substr($pageId, 0, strlen($pageId) - 6);
73
            } else {
74
                // try to resolve page 'sub' to sub-directory 'sub/'
75 3
                $pageId .= '/index';
76
            }
77 3
            $file = $folder . $pageId . $this->settings['content_ext'];
78
        }
79 14
        if (!file_exists($file)) {
80 2
            return null;
81
        }
82 13
        return $this->getPage($file, $folder);
83
    }
84
85
    /**
86
     * find all pages (*.md) files and returns an array of Page models
87
     *
88
     * @param array  $options
89
     * @param string $folder
90
     *
91
     * @return PageCollection of \Phile\Model\Page objects
92
     */
93 5
    public function findAll(array $options = array(), $folder = null)
94
    {
95 5
        $folder = $folder ?: $this->settings['content_dir'];
96 5
        return new PageCollection(
97 5
            function () use ($options, $folder) {
98 5
                $options += $this->settings;
99
                // ignore files with a leading '.' in its filename
100 5
                $files = Utility::getFiles($folder, '\Phile\FilterIterator\ContentFileFilterIterator');
101 5
                $pages = array();
102 5
                foreach ($files as $file) {
103 5
                    if (str_replace($folder, '', $file) == '404' . $this->settings['content_ext']) {
104
                        // jump to next page if file is the 404 page
105 5
                        continue;
106
                    }
107 5
                    $pages[] = $this->getPage($file, $folder);
108
                }
109
110 5
                if (empty($options['pages_order'])) {
111
                    return $pages;
112
                }
113
114
                // parse search	criteria
115 5
                $terms = preg_split('/\s+/', $options['pages_order'], -1, PREG_SPLIT_NO_EMPTY);
116 5
                foreach ($terms as $term) {
117 5
                    $sub = explode('.', $term);
118 5
                    if (count($sub) > 1) {
119 4
                        $type = array_shift($sub);
120
                    } else {
121 1
                        $type = null;
122
                    }
123 5
                    $sub = explode(':', $sub[0]);
124 5
                    if (count($sub) === 1) {
125 1
                        $sub[1] = 'asc';
126
                    }
127 5
                    $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...
128
                }
129
130
                // prepare search criteria for array_multisort
131 5
                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...
132 5
                    $key = $sort['key'];
133 5
                    $column = array();
134 5
                    foreach ($pages as $page) {
135
                        /**
136
            * @var \Phile\Model\Page $page
137
            */
138 5
                        $meta = $page->getMeta();
139 5
                        if ($sort['type'] === 'page') {
140
                            $method = 'get' . ucfirst($key);
141
                            $value = $page->$method();
142 5
                        } elseif ($sort['type'] === 'meta') {
143 4
                            $value = $meta->get($key);
144
                        } else {
145 1
                            trigger_error(
146 1
                                "Page order '{$sort['string']}' was ignored. Type '{$sort['type']}' not recognized.",
147 1
                                E_USER_WARNING
148
                            );
149
                            continue 2;
150
                        }
151 4
                        $column[] = $value;
152
                    }
153 4
                    $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...
154 4
                    $sortHelper[] = constant('SORT_' . strtoupper($sort['order']));
155
                }
156 4
                $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...
157
158 4
                call_user_func_array('array_multisort', $sortHelper);
159
160 4
                return $pages;
161 5
            }
162
        );
163
    }
164
165
    /**
166
     * return page at offset from $page in applied search order
167
     *
168
     * @param  \Phile\Model\Page $page
169
     * @param  int               $offset
170
     * @return null|\Phile\Model\Page
171
     */
172 2
    public function getPageOffset(\Phile\Model\Page $page, $offset = 0)
173
    {
174 2
        $pages = $this->findAll();
175 2
        $order = array();
176 2
        foreach ($pages as $p) {
177 2
            $order[] = $p->getFilePath();
178
        }
179 2
        $key = array_search($page->getFilePath(), $order) + $offset;
180 2
        if (!isset($order[$key])) {
181
            return null;
182
        }
183 2
        return $this->getPage($order[$key]);
184
    }
185
186
    /**
187
     * get page from cache or filepath
188
     *
189
     * @param $filePath
190
     * @param string   $folder
191
     *
192
     * @return mixed|\Phile\Model\Page
193
     */
194 15
    protected function getPage($filePath, $folder = null)
195
    {
196 15
        $folder = $folder ?: $this->settings['content_dir'];
197 15
        $key = 'Phile_Model_Page_' . md5($filePath);
198 15
        if (isset($this->storage[$key])) {
199 4
            return $this->storage[$key];
200
        }
201
202 15
        if ($this->cache !== null) {
203
            if ($this->cache->has($key)) {
204
                $page = $this->cache->get($key);
205
            } else {
206
                $page = new \Phile\Model\Page($filePath, $folder);
207
                $this->cache->set($key, $page);
208
            }
209
        } else {
210 15
            $page = new \Phile\Model\Page($filePath, $folder);
211
        }
212 15
        $this->storage[$key] = $page;
213
214 15
        return $page;
215
    }
216
}
217