Completed
Branch #338-Save_posting_before_movin... (2366dc)
by Schlaefer
02:58
created

PostingBehavior::updatePosting()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 3
dl 0
loc 29
rs 9.456
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
            if (empty($data['category_id'])) {
69
                throw new \InvalidArgumentException(
70
                    'New root posting requires a category.',
71
                    1564756572
72
                );
73
            }
74
        }
75
76
        /// set user who created the posting
77
        $data['user_id'] = $CurrentUser->getId();
78
        $data['name'] = $CurrentUser->get('username');
79
80
        $this->validatorSetup($CurrentUser);
81
82
        /** @var EntriesTable */
83
        $table = $this->getTable();
84
85
        return $table->createEntry($data);
86
    }
87
88
    /**
89
     * Updates an existing posting
90
     *
91
     * @param Entry $posting the posting to update
92
     * @param array $data data the posting should be updated with
93
     * @param CurrentUserInterface $CurrentUser the current-user
94
     * @return Entry the posting which was asked to update
95
     */
96
    public function updatePosting(Entry $posting, array $data, CurrentUserInterface $CurrentUser): Entry
97
    {
98
        $data = $this->fieldFilter->filterFields($data, 'update');
99
        $isRoot = $posting->isRoot();
100
        $parent = $this->getTable()->get($posting->get('pid'));
101
102
        if (!$isRoot) {
103
            $data = $this->prepareChildPosting($parent, $data);
104
        }
105
106
        $data['edited_by'] = $CurrentUser->get('username');
107
108
        /// must be set for validation
109
        $data['time'] = $posting->get('time');
110
        $data['user_id'] = $posting->get('user_id');
111
        $data['locked'] = $posting->get('locked');
112
113
        $this->validatorSetup($CurrentUser);
114
        $this->getTable()->getValidator()->add(
115
            'edited_by',
116
            'isEditingAllowed',
117
            ['rule' => [$this, 'validateEditingAllowed']]
118
        );
119
120
        /** @var EntriesTable */
121
        $table = $this->getTable();
122
123
        return $table->updateEntry($posting, $data);
124
    }
125
126
    /**
127
     * Populates data of an answer derived from parent the parent-posting
128
     *
129
     * @param BasicPostingInterface $parent parent data
130
     * @param array $data current posting data
131
     * @return array populated $data
132
     */
133
    public function prepareChildPosting(BasicPostingInterface $parent, array $data): array
134
    {
135
        if (empty($data['subject'])) {
136
            /// if new subject is empty use the parent's subject
137
            $data['subject'] = $parent->get('subject');
138
        }
139
140
        $data['tid'] = $parent->get('tid');
141
        $data['category_id'] = $parent->get('category_id');
142
143
        return $data;
144
    }
145
146
    /**
147
     * Sets-up validator for the table
148
     *
149
     * @param CurrentUserInterface $CurrentUser current user
150
     * @return void
151
     */
152
    private function validatorSetup(CurrentUserInterface $CurrentUser): void
153
    {
154
        $this->CurrentUser = $CurrentUser;
155
156
        $this->getTable()->getValidator()->add(
157
            'category_id',
158
            'isAllowed',
159
            ['rule' => [$this, 'validateCategoryIsAllowed']]
160
        );
161
    }
162
163
    /**
164
     * check that entries are only in existing and allowed categories
165
     *
166
     * @param mixed $categoryId value
167
     * @param array $context context
168
     * @return bool
169
     */
170
    public function validateCategoryIsAllowed($categoryId, $context): bool
171
    {
172
        $isRoot = $context['data']['pid'] == 0;
173
        $action = $isRoot ? 'thread' : 'answer';
174
175
        // @td better return !$posting->isAnsweringForbidden();
176
        return $this->CurrentUser->getCategories()->permission($action, $categoryId);
177
    }
178
179
    /**
180
     * check editing allowed
181
     *
182
     * @param mixed $check value
183
     * @param array $context context
184
     * @return bool
185
     */
186
    public function validateEditingAllowed($check, $context): bool
187
    {
188
        $posting = new Posting($this->CurrentUser, $context['data']);
189
190
        return $posting->isEditingAllowed();
191
    }
192
}
193