Passed
Push — master ( 37fbce...eb9638 )
by Mihail
09:07
created

Apps/Model/Admin/Content/FormContentUpdate.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Apps\Model\Admin\Content;
4
5
use Apps\ActiveRecord\Content;
6
use Apps\ActiveRecord\ContentCategory;
7
use Ffcms\Core\App;
8
use Ffcms\Core\Arch\Model;
9
use Ffcms\Core\Helper\Date;
10
use Ffcms\Core\Helper\FileSystem\Directory;
11
use Ffcms\Core\Helper\FileSystem\File;
12
use Ffcms\Core\Helper\Type\Integer;
13
use Ffcms\Core\Helper\Type\Obj;
14
use Ffcms\Core\Helper\Serialize;
15
use Ffcms\Core\Helper\Type\Str;
16
17
class FormContentUpdate extends Model
18
{
19
    public $title = [];
20
    public $text = [];
21
    public $path;
22
    public $poster;
23
    public $categoryId;
24
    public $authorId;
25
    public $metaTitle;
26
    public $metaKeywords = [];
27
    public $metaDescription = [];
28
    public $display = '1';
29
    public $source;
30
    public $addRating = 0;
31
    public $createdAt;
32
33
    public $galleryFreeId;
34
35
36
    private $_content;
37
    private $_new = false;
38
39
    public function __construct(Content $content)
40
    {
41
        $this->_content = $content;
42
        parent::__construct();
43
    }
44
45
    /**
46
    * Set model properties from active record data
47
    */
48
    public function before()
49
    {
50
        // is new item?
51
        if ($this->_content->id === null) {
52
            $this->_new = true;
53
            if (null === $this->galleryFreeId) {
54
                $this->galleryFreeId = '_tmp_' . Str::randomLatin(mt_rand(16, 32));
55
            }
56
            if (null === $this->authorId) {
57
                $this->authorId = App::$User->identity()->getId();
58
            }
59
            if (null === $this->categoryId) {
60
                $this->categoryId = 1;
61
            }
62
        } else { // is edit of exist item? define available data
63
            $this->title = Serialize::decode($this->_content->title);
64
            $this->text = Serialize::decode($this->_content->text);
65
            $this->path = $this->_content->path;
66
            $this->poster = $this->_content->poster;
67
            $this->categoryId = $this->_content->category_id;
68
            $this->authorId = $this->_content->author_id;
69
            $this->metaTitle = Serialize::decode($this->_content->meta_title);
70
            $this->metaKeywords = Serialize::decode($this->_content->meta_keywords);
71
            $this->metaDescription = Serialize::decode($this->_content->meta_description);
72
            $this->display = $this->_content->display;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->_content->display can also be of type integer. However, the property $display is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
73
            $this->source  = $this->_content->source;
74
            $this->createdAt = Date::convertToDatetime($this->_content->created_at, Date::FORMAT_TO_HOUR);
0 ignored issues
show
It seems like $this->_content->created_at can also be of type boolean; however, Ffcms\Core\Helper\Date::convertToDatetime() does only seem to accept string|integer, 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...
75
            $this->galleryFreeId = $this->_content->id;
76
        }
77
    }
78
79
    /**
80
     * Validation rules
81
     */
82
    public function rules()
83
    {
84
        $res =  [
85
            ['title.' . App::$Request->getLanguage(), 'required'],
86
            ['text.' . App::$Request->getLanguage(), 'required', null, true, true],
87
            ['text', 'used', null, true, true],
88
            ['path', 'reverse_match', '/[\/\'~`\!@#\$%\^&\*\(\)+=\{\}\[\]\|;:"\<\>,\?\\\]/'],
89
            [['path', 'categoryId', 'authorId', 'display', 'galleryFreeId', 'title'], 'required'],
90
            [['metaTitle', 'metaKeywords', 'metaDescription', 'poster', 'source', 'addRating', 'createdAt'], 'used'],
91
            [['addRating', 'authorId', 'display'], 'int'],
92
            ['display', 'in', ['0', '1']],
93
            ['categoryId', 'in', $this->categoryIds()],
94
            ['path', '\Apps\Model\Admin\Content\FormContentUpdate::validatePath'],
95
            ['authorId', '\App::$User::isExist']
96
        ];
97
98
        foreach (App::$Properties->get('languages') as $lang) {
99
            $res[] = ['title.' . $lang, 'length_max', 120, null, true, true];
100
            $res[] = ['keywords.' . $lang, 'length_max', 150];
101
            $res[] = ['description.' . $lang, 'length_max', 250];
102
        }
103
104
        return $res;
105
    }
106
107
    /**
108
    * Labels
109
    */
110
    public function labels()
111
    {
112
        return [
113
            'title' => __('Content title'),
114
            'text' => __('Content text'),
115
            'path' => __('Path slug'),
116
            'categoryId' => __('Category'),
117
            'metaTitle' => __('Meta title'),
118
            'metaKeywords' => __('Meta keywords'),
119
            'metaDescription' => __('Meta description'),
120
            'display' => __('Public display'),
121
            'createdAt' => __('Publish date'),
122
            'authorId' => __('Author identity'),
123
            'source' => __('Source URL'),
124
            'addRating' => __('Change rating'),
125
            'poster' => __('Poster')
126
        ];
127
    }
128
129
    /**
130
     * Save changes in database
131
     */
132
    public function save()
133
    {
134
        $this->_content->title = Serialize::encode(App::$Security->strip_tags($this->title));
135
        $this->_content->text = Serialize::encode($this->text);
136
        $this->_content->path = $this->path;
137
        $this->_content->category_id = $this->categoryId;
138
        $this->_content->author_id = $this->authorId;
139
        $this->_content->display = $this->display;
140
        $this->_content->meta_title = Serialize::encode(App::$Security->strip_tags($this->metaTitle));
141
        $this->_content->meta_keywords = Serialize::encode(App::$Security->strip_tags($this->metaKeywords));
142
        $this->_content->meta_description = Serialize::encode(App::$Security->strip_tags($this->metaDescription));
143
        $this->_content->source = App::$Security->strip_tags($this->source);
144
        // check if rating is changed
145
        if ((int)$this->addRating !== 0) {
146
            $this->_content->rating += (int)$this->addRating;
147
        }
148
        // check if special comment hash is exist
149
        if ($this->_new || Str::length($this->_content->comment_hash) < 32) {
150
            $this->_content->comment_hash = $this->generateCommentHash();
151
        }
152
        // check if date is updated
153
        if (!Str::likeEmpty($this->createdAt) && !Str::startsWith('0000', Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP))) {
154
            $this->_content->created_at = Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP);
155
        }
156
157
        // save poster data
158
        $posterPath = '/upload/gallery/' . $this->galleryFreeId . '/orig/' . $this->poster;
159
        if (File::exist($posterPath)) {
160
            $this->_content->poster = $this->poster;
161
        }
162
163
        // get temporary gallery id
164
        $tmpGalleryId = $this->galleryFreeId;
165
166
        // save row
167
        $this->_content->save();
168
169
        // move files
170
        if ($tmpGalleryId !== $this->_content->id) {
171
            Directory::rename('/upload/gallery/' . $tmpGalleryId, $this->_content->id);
172
        }
173
    }
174
175
    /**
176
     * Get allowed category ids as array (string values for validation)
177
     * @return array
178
     */
179 View Code Duplication
    public function categoryIds()
180
    {
181
        $data = ContentCategory::getSortedCategories();
182
        $response = [];
183
        foreach ($data as $key=>$val) {
184
            $response[] = (string)$key;
185
        }
186
        return $response;
187
    }
188
189
    /**
190
     * Validate path filter
191
     * @return bool
192
     */
193
    public function validatePath()
194
    {
195
        // try to find this item
196
        $find = Content::where('path', '=', $this->path);
197
        // exclude self id
198
        if ($this->_content->id !== null && Obj::isLikeInt($this->_content->id)) {
199
            $find->where('id', '!=', $this->_content->id);
200
        }
201
        // limit only current category id
202
        $find->where('category_id', '=', $this->categoryId);
203
204
        return $find->count() < 1;
205
    }
206
207
    /**
208
     * Generate random string for comment hash value
209
     * @return string
210
     */
211
    private function generateCommentHash()
212
    {
213
        $hash = Str::randomLatinNumeric(mt_rand(32, 128));
214
        $find = Content::where('comment_hash', '=', $hash)->count();
215
        // hmmm, is always exist? Chance of it is TOOOO low, but lets recursion re-generate
216
        if ($find !== 0) {
217
            return $this->generateCommentHash();
218
        }
219
220
        return $hash;
221
    }
222
}