Completed
Push — master ( fd5325...d7e193 )
by Schlaefer
05:54 queued 03:00
created

PostingBehavior::updatePosting()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 3
dl 0
loc 30
rs 9.44
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Saito - The Threaded Web Forum
7
 *
8
 * @copyright Copyright (c) the Saito Project Developers
9
 * @link https://github.com/Schlaefer/Saito
10
 * @license http://opensource.org/licenses/MIT
11
 */
12
13
namespace App\Model\Behavior;
14
15
use App\Lib\Model\Table\FieldFilter;
16
use App\Model\Entity\Entry;
17
use App\Model\Table\EntriesTable;
18
use Cake\ORM\Behavior;
19
use Saito\Posting\Basic\BasicPostingInterface;
20
use Saito\Posting\Posting;
21
use Saito\User\CurrentUser\CurrentUserInterface;
22
23
class PostingBehavior extends Behavior
24
{
25
    /** @var CurrentUserInterface */
26
    private $CurrentUser;
27
28
    /** @var FieldFilter */
29
    private $fieldFilter;
30
31
    /**
32
     * {@inheritDoc}
33
     */
34
    public function initialize(array $config)
35
    {
36
        $this->fieldFilter = (new fieldfilter())
37
            ->setConfig('create', ['category_id', 'pid', 'subject', 'text'])
38
            ->setConfig('update', ['category_id', 'subject', 'text']);
39
    }
40
41
    /**
42
     * Creates a new posting from user
43
     *
44
     * @param array $data raw posting data
45
     * @param CurrentUserInterface $CurrentUser the current user
46
     * @return Entry|null on success, null otherwise
47
     */
48
    public function createPosting(array $data, CurrentUserInterface $CurrentUser): ?Entry
49
    {
50
        $data = $this->fieldFilter->filterFields($data, 'create');
51
52
        if (!empty($data['pid'])) {
53
            /// new posting is answer to existing posting
54
            $parent = $this->getTable()->get($data['pid']);
55
56
            if (empty($parent)) {
57
                throw new \InvalidArgumentException(
58
                    'Parent posting for creating a new answer not found.',
59
                    1564756571
60
                );
61
            }
62
63
            $data = $this->prepareChildPosting($parent, $data);
64
        } else {
65
            /// if no pid is provided the new posting is root-posting
66
            $data['pid'] = 0;
67
        }
68
69
        /// set user who created the posting
70
        $data['user_id'] = $CurrentUser->getId();
71
        $data['name'] = $CurrentUser->get('username');
72
73
        $this->validatorSetup($CurrentUser);
74
75
        /** @var EntriesTable */
76
        $table = $this->getTable();
77
78
        return $table->createEntry($data);
79
    }
80
81
    /**
82
     * Updates an existing posting
83
     *
84
     * @param Entry $posting the posting to update
85
     * @param array $data data the posting should be updated with
86
     * @param CurrentUserInterface $CurrentUser the current-user
87
     * @return Entry|null the posting which was asked to update
88
     */
89
    public function updatePosting(Entry $posting, array $data, CurrentUserInterface $CurrentUser): ?Entry
90
    {
91
        $data = $this->fieldFilter->filterFields($data, 'update');
92
        $isRoot = $posting->isRoot();
93
        $parent = $this->getTable()->get($posting->get('pid'));
94
95
        if (!$isRoot) {
96
            $data = $this->prepareChildPosting($parent, $data);
97
        }
98
99
        $data['edited_by'] = $CurrentUser->get('username');
100
101
        /// must be set for validation
102
        $data['locked'] = $posting->get('locked');
103
        $data['pid'] = $posting->get('pid');
104
        $data['time'] = $posting->get('time');
105
        $data['user_id'] = $posting->get('user_id');
106
107
        $this->validatorSetup($CurrentUser);
108
        $this->getTable()->getValidator()->add(
109
            'edited_by',
110
            'isEditingAllowed',
111
            ['rule' => [$this, 'validateEditingAllowed']]
112
        );
113
114
        /** @var EntriesTable */
115
        $table = $this->getTable();
116
117
        return $table->updateEntry($posting, $data);
118
    }
119
120
    /**
121
     * Populates data of an answer derived from parent the parent-posting
122
     *
123
     * @param BasicPostingInterface $parent parent data
124
     * @param array $data current posting data
125
     * @return array populated $data
126
     */
127
    public function prepareChildPosting(BasicPostingInterface $parent, array $data): array
128
    {
129
        if (empty($data['subject'])) {
130
            // if new subject is empty use the parent's subject
131
            $data['subject'] = $parent->get('subject');
132
        }
133
134
        $data['category_id'] = $parent->get('category_id');
135
        $data['tid'] = $parent->get('tid');
136
137
        return $data;
138
    }
139
140
    /**
141
     * Sets-up validator for the table
142
     *
143
     * @param CurrentUserInterface $CurrentUser current user
144
     * @return void
145
     */
146
    private function validatorSetup(CurrentUserInterface $CurrentUser): void
147
    {
148
        $this->CurrentUser = $CurrentUser;
149
150
        $this->getTable()->getValidator()->add(
151
            'category_id',
152
            'isAllowed',
153
            ['rule' => [$this, 'validateCategoryIsAllowed']]
154
        );
155
    }
156
157
    /**
158
     * check that entries are only in existing and allowed categories
159
     *
160
     * @param mixed $categoryId value
161
     * @param array $context context
162
     * @return bool
163
     */
164
    public function validateCategoryIsAllowed($categoryId, $context): bool
165
    {
166
        $isRoot = $context['data']['pid'] == 0;
167
        $action = $isRoot ? 'thread' : 'answer';
168
169
        // @td better return !$posting->isAnsweringForbidden();
170
        return $this->CurrentUser->getCategories()->permission($action, $categoryId);
171
    }
172
173
    /**
174
     * check editing allowed
175
     *
176
     * @param mixed $check value
177
     * @param array $context context
178
     * @return bool
179
     */
180
    public function validateEditingAllowed($check, $context): bool
181
    {
182
        $posting = new Posting($this->CurrentUser, $context['data']);
183
184
        return $posting->isEditingAllowed();
185
    }
186
}
187