Passed
Push — master ( 087cc0...37fbce )
by Mihail
04:19
created

EntityCategoryList::buildOutput()   F

Complexity

Conditions 13
Paths 645

Size

Total Lines 99
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 99
rs 2.4575
cc 13
eloc 60
nc 645
nop 1

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
namespace Apps\Model\Front\Content;
4
5
6
use Apps\ActiveRecord\ContentCategory;
7
use Apps\ActiveRecord\Content as ContentRecord;
8
use Apps\ActiveRecord\User;
9
use Ffcms\Core\App;
10
use Ffcms\Core\Arch\Model;
11
use Ffcms\Core\Exception\ForbiddenException;
12
use Ffcms\Core\Exception\NotFoundException;
13
use Ffcms\Core\Helper\Date;
14
use Ffcms\Core\Helper\FileSystem\File;
15
use Ffcms\Core\Helper\Serialize;
16
use Ffcms\Core\Helper\Type\Arr;
17
use Ffcms\Core\Helper\Type\Obj;
18
use Ffcms\Core\Helper\Type\Str;
19
20
/**
21
 * Class EntityCategoryList. Build content and category data to display in views based on pathway.
22
 * @package Apps\Model\Front\Content
23
 */
24
class EntityCategoryList extends Model
25
{
26
    // page breaker to split short and full content
27
    const PAGE_BREAK = '<div style="page-break-after: always">';
28
29
    // properties to display: content item collection, category data, etc
30
    public $items;
31
    public $category;
32
    public $categories;
33
34
    // private items used on model building
35
    private $_path;
36
    private $_configs;
37
    private $_page = 0;
38
    private $_contentCount = 0;
39
40
    private $_currentCategory;
41
    private $_allCategories;
42
    private $_catIds;
43
44
    /**
45
     * EntityCategoryList constructor. Pass pathway as string and data of multi-category system
46
     * @param string $path
47
     * @param array $configs
48
     * @param int $offset
49
     */
50
    public function __construct($path, array $configs, $offset = 0)
51
    {
52
        $this->_path = $path;
53
        $this->_configs = $configs;
54
        $this->_page = (int)$offset;
55
        parent::__construct();
56
    }
57
58
    /**
59
     * Build model properties
60
     * @throws ForbiddenException
61
     * @throws NotFoundException
62
     */
63
    public function before()
64
    {
65
        // find one or more categories where we must looking for content items
66
        if ((int)$this->_configs['multiCategories'] === 1) {
67
            $this->findCategories();
68
        } else {
69
            $this->findCategory();
70
        }
71
72
        // try to find content items depend of founded category(ies)
73
        $records = $this->findItems();
74
        // prepare output data
75
        $this->buildOutput($records);
76
    }
77
78
    /**
79
     * Find current category data
80
     * @throws NotFoundException
81
     */
82
    private function findCategory()
83
    {
84
        // get current category
85
        $query = ContentCategory::where('path', '=', $this->_path);
86
        if ($query->count() !== 1) {
87
            throw new NotFoundException(__('Category is not founded'));
88
        }
89
90
        // set properties from query
91
        $this->_allCategories = $query->get();
92
        $this->_currentCategory = $query->first();
93
        $this->_catIds[] = $this->_currentCategory['id'];
94
    }
95
96
    /**
97
     * Find multiple categories child of current
98
     * @throws NotFoundException
99
     */
100
    private function findCategories()
101
    {
102
        // get all categories for current path and child of it
103
        $query = ContentCategory::where('path', 'like', $this->_path . '%');
104
        if ($query->count() < 1) {
105
            throw new NotFoundException(__('Category is not founded'));
106
        }
107
        // get result as object
108
        $result = $query->get();
109
110
        // extract ids from result as array by key id
111
        $this->_catIds = Arr::ploke('id', $result->toArray());
112
113
        // get current category matching
114
        foreach ($result as $row) {
115
            if ($row->path === $this->_path) {
116
                $this->_currentCategory = $row;
117
            }
118
        }
119
120
        // set result to property
121
        $this->_allCategories = $result;
122
    }
123
124
    /**
125
     * Find content items on database and return rows as object
126
     * @return mixed
127
     * @throws NotFoundException
128
     */
129
    private function findItems()
130
    {
131
        if (!Obj::isArray($this->_catIds) || count($this->_catIds) < 1) {
132
            throw new NotFoundException(__('Category is not founded'));
133
        }
134
135
        // calculate selection offset
136
        $itemPerPage = (int)$this->_configs['itemPerCategory'];
137
        if ($itemPerPage < 1) {
138
            $itemPerPage = 1;
139
        }
140
        $offset = $this->_page * $itemPerPage;
141
142
        // get all items from categories
143
        $query = ContentRecord::whereIn('category_id', $this->_catIds)
144
            ->where('display', '=', 1);
145
        // save count
146
        $this->_contentCount = $query->count();
147
148
        // make select based on offset
149
        return $query->skip($offset)->take($itemPerPage)->orderBy('created_at', 'DESC')->get();
150
    }
151
152
    /**
153
     * Build content data to model properties
154
     * @param $records
155
     * @throws ForbiddenException
156
     * @throws NotFoundException
157
     */
158
    private function buildOutput($records)
159
    {
160
        // prepare current category data to output (unserialize locales and strip tags)
161
        $this->category = [
162
            'title' => App::$Security->strip_tags(Serialize::getDecodeLocale($this->_currentCategory->title)),
0 ignored issues
show
Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...currentCategory->title) targeting Ffcms\Core\Helper\Serialize::getDecodeLocale() can also be of type null; however, Ffcms\Core\Helper\Security::strip_tags() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
163
            'description' => App::$Security->strip_tags(Serialize::getDecodeLocale($this->_currentCategory->description)),
0 ignored issues
show
Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...tCategory->description) targeting Ffcms\Core\Helper\Serialize::getDecodeLocale() can also be of type null; however, Ffcms\Core\Helper\Security::strip_tags() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
164
            'configs' => Serialize::decode($this->_currentCategory->configs),
165
            'path' => $this->_currentCategory->path
166
        ];
167
168
        // check if this category is hidden
169
        if ((int)$this->category['configs']['showCategory'] !== 1) {
170
            throw new ForbiddenException(__('This category is not available to view'));
171
        }
172
173
        // make sorted tree of categories to display in breadcrumbs
174
        foreach ($this->_allCategories as $cat) {
175
            $this->categories[$cat->id] = $cat;
176
        }
177
178
        $nullItems = 0;
179
        foreach ($records as $row) {
180
            // get full text
181
            $text = Serialize::getDecodeLocale($row->text);
182
            // try to find page breaker
183
            $breakPosition = mb_strpos($text, self::PAGE_BREAK, null, 'UTF-8');
184
            // offset is founded, try to split preview from full text
185
            if ($breakPosition !== false) {
186
                $text = Str::sub($text, 0, $breakPosition);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array or null; however, Ffcms\Core\Helper\Type\Str::sub() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
187
            } else { // page breaker is not founded, lets get a fun ;D
188
                // find first paragraph ending
189
                $breakPosition = mb_strpos($text, '</p>', null, 'UTF-8');
190
                // cut text from position caret before </p> (+4 symbols to save item as valid)
191
                $text = Str::sub($text, 0, $breakPosition+4);
0 ignored issues
show
Bug introduced by
It seems like $text can also be of type array or null; however, Ffcms\Core\Helper\Type\Str::sub() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
192
            }
193
194
            $itemPath = $this->categories[$row->category_id]->path;
195
            if (!Str::likeEmpty($itemPath)) {
196
                $itemPath .= '/';
197
            }
198
            $itemPath .= $row->path;
199
200
            // try to find poster and thumbnail for this content item
201
            $poster = $row->poster;
202
            $thumb = null;
203
            if (!Str::likeEmpty($poster)) {
204
                $thumbName = Str::cleanExtension($poster) . '.jpg';
205
                $poster = '/upload/gallery/' . $row->id . '/orig/' . $poster;
206
                $thumb = '/upload/gallery/' . $row->id . '/thumb/' . $thumbName;
207
                if (!File::exist($poster)) {
208
                    $poster = null;
209
                }
210
                if (!File::exist($thumb)) {
211
                    $thumb = null;
212
                }
213
            } else {
214
                $poster = null;
215
            }
216
217
            // prepare tags data
218
            $tags = Serialize::getDecodeLocale($row->meta_keywords);
219
            if (!Str::likeEmpty($tags)) {
0 ignored issues
show
Bug introduced by
It seems like $tags defined by \Ffcms\Core\Helper\Seria...le($row->meta_keywords) on line 218 can also be of type array or string; however, Ffcms\Core\Helper\Type\Str::likeEmpty() does only seem to accept null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
220
                $tags = explode(',', $tags);
221
            } else {
222
                $tags = null;
223
            }
224
225
            // check title length on current language locale
226
            $localeTitle = App::$Security->strip_tags(Serialize::getDecodeLocale($row->title));
0 ignored issues
show
Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...codeLocale($row->title) targeting Ffcms\Core\Helper\Serialize::getDecodeLocale() can also be of type null; however, Ffcms\Core\Helper\Security::strip_tags() does only seem to accept string|array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
227
            if (Str::length($localeTitle) < 1) {
0 ignored issues
show
Bug introduced by
It seems like $localeTitle defined by \Ffcms\Core\App::$Securi...odeLocale($row->title)) on line 226 can also be of type array; however, Ffcms\Core\Helper\Type\Str::length() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
228
                ++$nullItems;
229
            }
230
231
            $owner = App::$User->identity($row->author_id);
232
            // make a fake if user is not exist over id
233
            if ($owner === null) {
234
                $owner = new User();
235
            }
236
237
            // build result array
238
            $this->items[] = [
239
                'title' => $localeTitle,
240
                'text' => $text,
241
                'date' => Date::convertToDatetime($row->created_at, Date::FORMAT_TO_HOUR),
242
                'author' => $owner,
243
                'poster' => $poster,
244
                'thumb' => $thumb,
245
                'views' => (int)$row->views,
246
                'rating' => (int)$row->rating,
247
                'category' => $this->categories[$row->category_id],
248
                'uri' => '/content/read/' . $itemPath,
249
                'tags' => $tags
250
            ];
251
        }
252
253
        if ($nullItems === $this->_contentCount) {
254
            throw new NotFoundException(__('Content is not founded'));
255
        }
256
    }
257
258
    /**
259
     * Get content items count
260
     * @return int
261
     */
262
    public function getContentCount()
263
    {
264
        return $this->_contentCount;
265
    }
266
}