Passed
Push — master ( ba2801...f20f2e )
by Mihail
04:42
created

EntityCategoryList::buildOutput()   F

Complexity

Conditions 13
Paths 274

Size

Total Lines 95
Code Lines 57

Duplication

Lines 3
Ratio 3.16 %

Importance

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

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
180
            throw new ForbiddenException(__('This category is not available to view'));
181
        }
182
183
        // make sorted tree of categories to display in breadcrumbs
184
        foreach ($this->_allCategories as $cat) {
185
            $this->categories[$cat->id] = $cat;
186
        }
187
188
        $nullItems = 0;
189
        foreach ($records as $row) {
190
            /** @var Content $row */
191
            
192
            // check title length on current language locale
193
            $localeTitle = App::$Security->strip_tags($row->getLocaled('title'));
194
            if (Str::likeEmpty($localeTitle)) {
195
                ++$nullItems;
196
                continue;
197
            }
198
            
199
            // get snippet from full text for current locale
200
            $text = Text::snippet($row->getLocaled('text'));
201
202
            $itemPath = $this->categories[$row->category_id]->path;
203
            if (!Str::likeEmpty($itemPath)) {
204
                $itemPath .= '/';
205
            }
206
            $itemPath .= $row->path;
207
208
            // prepare tags data
209
            $tags = $row->getLocaled('meta_keywords');
210
            if (!Str::likeEmpty($tags)) {
211
                $tags = explode(',', $tags);
212
            } else {
213
                $tags = null;
214
            }
215
216
            $owner = App::$User->identity($row->author_id);
217
            // make a fake if user is not exist over id
218
            if ($owner === null) {
219
                $owner = new User();
220
            }
221
            
222
            // check if current user can rate item
223
            $ignoredRate = App::$Session->get('content.rate.ignore');
224
            $canRate = true;
225
            if (Obj::isArray($ignoredRate) && Arr::in((string)$row->id, $ignoredRate)) {
226
                $canRate = false;
227
            }
228
            if (!App::$User->isAuth()) {
229
                $canRate = false;
230
            }
231
            
232
            // build result array
233
            $this->items[] = [
234
                'id' => $row->id,
235
                'title' => $localeTitle,
236
                'text' => $text,
237
                'date' => Date::convertToDatetime($row->created_at, Date::FORMAT_TO_HOUR),
238
                'author' => $owner,
239
                'poster' => $row->getPosterUri(),
240
                'thumb' => $row->getPosterThumbUri(),
241
                'thumbSize' => File::size($row->getPosterThumbUri()),
242
                'views' => (int)$row->views,
243
                'rating' => (int)$row->rating,
244
                'canRate' => $canRate,
245
                'category' => $this->categories[$row->category_id],
246
                'uri' => '/content/read/' . $itemPath,
247
                'tags' => $tags
248
            ];
249
        }
250
251
        if ($nullItems === $this->_contentCount) {
252
            throw new NotFoundException(__('Content is not founded'));
253
        }
254
    }
255
256
    /**
257
     * Get content items count
258
     * @return int
259
     */
260
    public function getContentCount()
261
    {
262
        return $this->_contentCount;
263
    }
264
}