Passed
Branch master (249862)
by Adam
07:51
created

SubmitController   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 279
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 279
rs 9.3999
c 0
b 0
f 0
wmc 33

7 Methods

Rating   Name   Duplication   Size   Complexity  
A edit() 0 6 1
A savePoll() 0 11 4
B index() 0 20 6
C getDefaultText() 0 33 7
C save() 0 75 10
B subject() 0 67 4
A getPollRepository() 0 3 1
1
<?php
2
3
namespace Coyote\Http\Controllers\Forum;
4
5
use Coyote\Http\Controllers\Controller;
6
use Coyote\Http\Forms\Forum\SubjectForm;
7
use Coyote\Repositories\Contracts\PollRepositoryInterface;
8
use Coyote\Services\UrlBuilder\UrlBuilder;
9
use Illuminate\Http\Request;
10
use Coyote\Services\Stream\Activities\Create as Stream_Create;
11
use Coyote\Services\Stream\Activities\Update as Stream_Update;
12
use Coyote\Services\Stream\Objects\Topic as Stream_Topic;
13
use Coyote\Services\Stream\Objects\Post as Stream_Post;
14
use Coyote\Services\Stream\Objects\Forum as Stream_Forum;
15
use Coyote\Services\Stream\Actor as Stream_Actor;
16
use Coyote\Services\Parser\Helpers\Login as LoginHelper;
17
use Coyote\Events\PostWasSaved;
18
use Coyote\Events\TopicWasSaved;
19
use Coyote\Services\Notification\Container;
20
use Coyote\Post\Log;
21
22
class SubmitController extends BaseController
23
{
24
    /**
25
     * Show new post/edit form
26
     *
27
     * @param Request $request
28
     * @param \Coyote\Forum $forum
29
     * @param \Coyote\Topic $topic
30
     * @param \Coyote\Post|null $post
31
     * @return \Illuminate\View\View
32
     */
33
    public function index(Request $request, $forum, $topic, $post = null)
34
    {
35
        if (!empty($topic->id)) {
36
            $this->breadcrumb->push([
37
                $topic->subject => route('forum.topic', [$forum->slug, $topic->id, $topic->slug]),
38
                $post === null ? 'Odpowiedz' : 'Edycja' => url($request->path())
39
            ]);
40
        } else {
41
            $this->breadcrumb->push('Nowy wątek', route('forum.topic.submit', [$forum->slug]));
42
        }
43
44
        if (!empty($post)) {
45
            // make sure user can edit this post
46
            $this->authorize('update', [$post]);
47
        }
48
49
        $form = $this->getForm($forum, $topic, $post);
50
        $form->text->setValue($form->text->getValue() ?: ($topic ? $this->getDefaultText($request, $topic) : ''));
0 ignored issues
show
Bug Best Practice introduced by
The property text does not exist on Coyote\Http\Forms\Forum\PostForm. Since you implemented __get, consider adding a @property annotation.
Loading history...
introduced by
The condition $topic can never be true.
Loading history...
Bug introduced by
The method getValue() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

50
        $form->text->setValue($form->text->/** @scrutinizer ignore-call */ getValue() ?: ($topic ? $this->getDefaultText($request, $topic) : ''));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
51
52
        return Controller::view('forum.submit')->with(compact('forum', 'form', 'topic', 'post'));
0 ignored issues
show
Bug Best Practice introduced by
The method Coyote\Http\Controllers\Controller::view() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
        return Controller::/** @scrutinizer ignore-call */ view('forum.submit')->with(compact('forum', 'form', 'topic', 'post'));
Loading history...
53
    }
54
55
    /**
56
     * Show new post/edit form
57
     *
58
     * @param \Coyote\Forum $forum
59
     * @param \Coyote\Topic $topic
60
     * @param \Coyote\Post|null $post
61
     * @return mixed
62
     */
63
    public function save($forum, $topic, $post = null)
64
    {
65
        if (is_null($post)) {
66
            $post = $this->post->makeModel();
67
        } else {
68
            $this->authorize('update', [$post]);
69
        }
70
71
        $form = $this->getForm($forum, $topic, $post);
72
        $form->validate();
73
74
        return $this->transaction(function () use ($form, $forum, $topic, $post) {
75
            $request = $form->getRequest();
76
77
            $actor = new Stream_Actor($this->auth);
78
            if (auth()->guest()) {
79
                $actor->displayName = $request->get('user_name');
80
            }
81
82
            $poll = $this->savePoll($request, $topic->poll_id);
83
84
            $activity = $post->id ? new Stream_Update($actor) : new Stream_Create($actor);
85
            // saving post through repository... we need to pass few object to save relationships
86
            $this->post->save($form, $this->auth, $forum, $topic, $post, $poll);
87
88
            // url to the post
89
            $url = UrlBuilder::post($post);
90
91
            if ($post->wasRecentlyCreated) {
92
                $container = new Container();
93
                $notification = [
94
                    'sender_id' => $this->userId,
95
                    'sender_name' => $request->get('user_name', $this->userId ? $this->auth->name : ''),
96
                    'subject' => str_limit($topic->subject, 84),
97
                    'excerpt' => excerpt($post->html),
98
                    'url' => $url,
99
                    'text' => $post->html,
100
                    'topic_id' => $topic->id, // used to create unique notification object id
101
                    'post_id' => $post->id // used to create unique notification object id
102
                ];
103
104
                // $subscribersId can be int or array. we need to cast to array type
105
                $subscribersId = $forum->onlyUsersWithAccess($topic->subscribers()->pluck('user_id')->toArray());
106
                if ($subscribersId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $subscribersId of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
107
                    $container->attach(
108
                        app('notification.topic.subscriber')->with($notification)->setUsersId($subscribersId)
109
                    );
110
                }
111
112
                // get id of users that were mentioned in the text
113
                $subscribersId = $forum->onlyUsersWithAccess((new LoginHelper())->grab($post->html));
0 ignored issues
show
Bug introduced by
It seems like $post->html can also be of type Illuminate\Database\Eloq...uent\Relations\Relation and Illuminate\Database\Eloquent\Relations\Relation; however, parameter $html of Coyote\Services\Parser\Helpers\Login::grab() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

113
                $subscribersId = $forum->onlyUsersWithAccess((new LoginHelper())->grab(/** @scrutinizer ignore-type */ $post->html));
Loading history...
114
                if ($subscribersId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $subscribersId of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
115
                    $container->attach(app('notification.post.login')->with($notification)->setUsersId($subscribersId));
116
                }
117
118
                $container->notify();
119
            }
120
121
            if ($topic->wasRecentlyCreated || $post->id === $topic->first_post_id) {
122
                $object = (new Stream_Topic)->map($topic, $post->html);
0 ignored issues
show
Bug introduced by
It seems like $post->html can also be of type Illuminate\Database\Eloq...uent\Relations\Relation and Illuminate\Database\Eloquent\Relations\Relation; however, parameter $text of Coyote\Services\Stream\Objects\Topic::map() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

122
                $object = (new Stream_Topic)->map($topic, /** @scrutinizer ignore-type */ $post->html);
Loading history...
123
                $target = (new Stream_Forum)->map($forum);
124
            } else {
125
                $object = (new Stream_Post(['url' => $url]))->map($post);
126
                $target = (new Stream_Topic())->map($topic);
127
            }
128
129
            stream($activity, $object, $target);
130
131
            // fire the event. it can be used to index a content and/or add page path to "pages" table
132
            event(new TopicWasSaved($topic));
133
            // add post to elasticsearch
134
            event(new PostWasSaved($post));
135
136
            $request->attributes->set('url', $url);
137
            return $post;
138
        });
139
    }
140
141
    /**
142
     * @param Request $request
143
     * @param int $pollId
144
     * @return \Coyote\Poll|null
145
     */
146
    private function savePoll(Request $request, $pollId)
147
    {
148
        if ($request->input('poll.remove')) {
149
            $this->getPollRepository()->delete($pollId);
150
        } elseif ($request->has('poll.title')) {
151
            return $this->getPollRepository()->updateOrCreate($pollId, $request->input('poll'));
152
        } elseif ($pollId) {
153
            return $this->getPollRepository()->find($pollId);
154
        }
155
156
        return null;
157
    }
158
159
    /**
160
     * @return PollRepositoryInterface
161
     */
162
    private function getPollRepository()
163
    {
164
        return app(PollRepositoryInterface::class);
165
    }
166
167
    /**
168
     * Ajax request. Display edit form
169
     *
170
     * @param $forum
171
     * @param $topic
172
     * @param $post
173
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
174
     */
175
    public function edit($forum, $topic, $post)
176
    {
177
        $this->authorize('update', [$post]);
178
        $form = $this->getForm($forum, $topic, $post);
179
180
        return view('forum.partials.edit')->with('form', $form);
181
    }
182
183
    /**
184
     * @param \Coyote\Topic $topic
185
     * @param SubjectForm $form
186
     * @return \Symfony\Component\HttpFoundation\Response
187
     *
188
     * @todo moze jakas refaktoryzacja? przeniesienie do repozytorium? na pewno logowanie o tym, ze zostal zmieniony
189
     * tytul a nie tresc posta (jak to jest obecnie)
190
     */
191
    public function subject($topic, SubjectForm $form)
192
    {
193
        /** @var \Coyote\Forum $forum */
194
        $forum = $topic->forum()->first();
195
        $this->authorize('update', $forum);
196
197
        $request = $form->getRequest();
198
199
        $url = $this->transaction(function () use ($request, $forum, $topic) {
200
            $topic->fill(['subject' => $request->get('subject')]);
201
202
            /** @var \Coyote\Post $post */
203
            $post = $topic->firstPost()->first();
204
            $url = route('forum.topic', [$forum->slug, $topic->id, $topic->slug], false);
205
206
            if ($topic->isDirty()) {
207
                $original = $topic->getOriginal();
208
209
                $topic->save();
210
                $tags = $topic->getTagNames();
211
212
                // save it in log...
213
                (new Log)
214
                    ->fillWithPost($post)
215
                    ->fill(['user_id' => $this->userId, 'subject' => $topic->subject, 'tags' => $tags])
216
                    ->save();
217
218
                $post->fill([
219
                    'edit_count' => $post->edit_count + 1, 'editor_id' => $this->userId
220
                ])
221
                ->save();
222
223
                if ($post->user_id) {
224
                    app('notification.topic.subject')->with([
225
                        'users_id'    => $forum->onlyUsersWithAccess([$post->user_id]),
226
                        'sender_id'   => $this->userId,
227
                        'sender_name' => $this->auth->name,
228
                        'subject'     => str_limit($original['subject'], 84),
229
                        'excerpt'     => str_limit($topic->subject, 84),
230
                        'url'         => $url,
231
                        'topic_id'    => $topic->id
232
                    ])->notify();
233
                }
234
235
                // fire the event. it can be used to index a content and/or add page path to "pages" table
236
                event(new TopicWasSaved($topic));
237
                // add post to elasticsearch
238
                event(new PostWasSaved($post));
239
            }
240
241
            // get text from cache to put excerpt in stream activity
242
            $post->text = app('parser.post')->parse($post->text);
243
244
            // put action into activity stream
245
            stream(
246
                Stream_Update::class,
247
                (new Stream_Topic)->map($topic, $post->text),
248
                (new Stream_Forum)->map($forum)
249
            );
250
251
            return $url;
252
        });
253
254
        if ($request->ajax()) {
255
            return response(url($url));
0 ignored issues
show
Bug introduced by
It seems like url($url) can also be of type Illuminate\Contracts\Routing\UrlGenerator; however, parameter $content of response() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

255
            return response(/** @scrutinizer ignore-type */ url($url));
Loading history...
Bug Best Practice introduced by
The expression return response(url($url)) also could return the type Illuminate\Contracts\Routing\ResponseFactory which is incompatible with the documented return type Symfony\Component\HttpFoundation\Response.
Loading history...
256
        } else {
257
            return redirect()->to($url);
258
        }
259
    }
260
261
    /**
262
     * Format post text in case of quoting
263
     *
264
     * @param Request $request
265
     * @param \Coyote\Topic $topic
266
     * @return string
267
     */
268
    protected function getDefaultText(Request $request, $topic)
269
    {
270
        $text = '';
271
272
        // IDs of posts that user want to quote...
273
        $postsId = [];
274
        $cookie = isset($_COOKIE['mqid' . $topic->id]) ? $_COOKIE['mqid' . $topic->id] : null;
275
276
        if ($cookie) {
277
            $postsId = array_map('intval', explode(',', $cookie));
278
            // I used raw PHP function because I don't want to use laravel encryption in this case
279
            setcookie('mqid' . $topic->id, null, time() - 3600, '/');
280
        }
281
282
        if ($request->input('quote')) {
283
            $postsId[] = $request->input('quote');
284
        }
285
286
        if (!empty($postsId)) {
287
            $posts = $this->post->findPosts(array_unique($postsId), $topic->id);
288
289
            // builds text with quoted posts
290
            foreach ($posts as $post) {
291
                $text .= '> ##### [' .
292
                    ($post->name ?: $post->user_name) .
293
                    ' napisał(a)](' . route('forum.share', [$post->id]) . '):';
294
295
                $text .= "\n> " . str_replace("\n", "\n> ", $post->text);
296
                $text .= "\n\n";
297
            }
298
        }
299
300
        return $text;
301
    }
302
}
303