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

FormContentUpdate::generateCommentHash()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 0
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);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...$this->_content->title) can also be of type string. However, the property $title is declared as type array. 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...
64
            $this->text = Serialize::decode($this->_content->text);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...($this->_content->text) can also be of type string. However, the property $text is declared as type array. 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...
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);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...content->meta_keywords) can also be of type string. However, the property $metaKeywords is declared as type array. 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...
71
            $this->metaDescription = Serialize::decode($this->_content->meta_description);
0 ignored issues
show
Documentation Bug introduced by
It seems like \Ffcms\Core\Helper\Seria...tent->meta_description) can also be of type string. However, the property $metaDescription is declared as type array. 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...
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
Bug introduced by
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))) {
0 ignored issues
show
Bug introduced by
It seems like $this->createdAt 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...
Bug introduced by
It seems like \Ffcms\Core\Helper\Date:...::FORMAT_SQL_TIMESTAMP) targeting Ffcms\Core\Helper\Date::convertToDatetime() can also be of type boolean; however, Ffcms\Core\Helper\Type\Str::startsWith() does only seem to accept string, 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...
154
            $this->_content->created_at = Date::convertToDatetime($this->createdAt, Date::FORMAT_SQL_TIMESTAMP);
0 ignored issues
show
Bug introduced by
It seems like $this->createdAt 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...
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()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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
    {
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
}