- <?php
-
- declare(strict_types=1);
-
- namespace App\Controllers;
-
- use App\Models\File;
- use App\Models\Story;
- use App\Models\StoryTag;
- use App\Models\Tag;
- use App\Repositories\FileRepository;
- use App\Repositories\ReadRepository;
- use App\Repositories\StoryRepository;
- use App\Services\Session;
- use App\Services\Slug;
- use App\Services\Str;
- use App\Services\Validator;
- use App\Services\View;
- use Psr\Http\Message\ResponseInterface as Response;
- use Psr\Http\Message\ServerRequestInterface as Request;
-
- /**
- * StoryController
- */
- class StoryController extends Controller
- {
- public function __construct(
- protected View $view,
- protected Session $session,
- protected Validator $validator,
- protected FileRepository $fileRepository,
- protected StoryRepository $storyRepository,
- protected ReadRepository $readRepository,
- ) {}
-
- /**
- * Index
- *
- * @param Response $response
- *
- * @return Response
- */
- public function index(Response $response): Response
- {
- $stories = $this->storyRepository->getStories(setting('story.per_page'));
-
- return $this->view->render(
- $response,
- 'stories/index',
- compact('stories')
- );
- }
-
- /**
- * View
- *
- * @param string $slug
- * @param Request $request
- * @param Response $response
- *
- * @return Response
- */
- public function view(string $slug, Request $request, Response $response): Response
- {
- $story = $this->storyRepository->getBySlug($slug);
- if (! $story) {
- abort(404, 'Статья не найдена!');
- }
-
- // Count reads
- $this->readRepository->createRead($story, $request->getAttribute('ip'));
-
- $files = $this->fileRepository->getFilesByStoryId($story->id);
-
- return $this->view->render(
- $response,
- 'stories/view',
- compact('story', 'files')
- );
- }
-
- /**
- * Create
- *
- * @param Response $response
- *
- * @return Response
- */
- public function create(Response $response): Response
- {
- if (! setting('story.allow_posting') && ! isAdmin()) {
- abort(403, 'Публикация статей запрещена администратором!');
- }
-
- $user = getUser();
- $files = $this->fileRepository->getFiles($user->id, 0);
-
- return $this->view->render(
- $response,
- 'stories/create',
- compact('files')
- );
- }
-
- /**
- * Store
- *
- * @param Request $request
- * @param Response $response
- * @param Slug $slug
- *
- * @return Response
- */
- public function store(
- Request $request,
- Response $response,
- Slug $slug,
- ): Response {
- $user = getUser();
- $input = (array) $request->getParsedBody();
- $tags = array_map('sanitize', $input['tags'] ?? []);
-
- $this->validator
- ->required(['csrf', 'title', 'text', 'tags'])
- ->same('csrf', $this->session->get('csrf'), 'Неверный идентификатор сессии, повторите действие!')
- ->length('title', setting('story.title_min_length'), setting('story.title_max_length'))
- ->length('text', setting('story.text_min_length'), setting('story.text_max_length'))
- ->custom(count($tags) <= setting('story.tags_max'), ['tags' => 'Превышено максимальное количество тегов'])
- ->boolean('locked');
-
- foreach ($tags as $tag) {
- $this->validator->custom(
- Str::length($tag) >= setting('story.tags_min_length') && Str::length($tag) <= setting('story.tags_max_length'),
- ['tags' => sprintf('Длина тегов должна быть от %d до %d символов!', setting('story.tags_min_length'), setting('story.tags_max_length'))]
- );
- }
-
- if ($this->validator->isValid($input)) {
- $slugify = $slug->slugify($input['title']);
-
- $story = Story::query()->create([
- 'user_id' => $user->id,
- 'title' => sanitize($input['title']),
- 'slug' => $slugify,
- 'text' => sanitize($input['text']),
- 'rating' => 0,
- 'reads' => 0,
- 'locked' => isAdmin() ? $input['locked'] ?? 0 : 0,
- 'created_at' => time(),
- ]);
-
- foreach ($tags as $value) {
- Tag::query()->create([
- 'story_id' => $story->id,
- 'tag' => Str::lower($value),
- ]);
- }
-
- File::query()
- ->where('story_id', 0)
- ->where('user_id', $user->id)
- ->update(['story_id' => $story->id]);
-
- $this->session->set('flash', ['success' => 'Статья успешно добавлена!']);
-
- return $this->redirect($response, $story->getLink());
- }
-
- $this->session->set('flash', ['errors' => $this->validator->getErrors(), 'old' => $input]);
-
- return $this->redirect($response, '/create');
- }
-
- /**
- * Edit
- *
- * @param int $id
- * @param Response $response
- *
- * @return Response
- */
- public function edit(int $id, Response $response): Response
- {
- $user = getUser();
-
- $story = $this->storyRepository->getById($id);
- if (! $story) {
- abort(404, 'Статья не найдена!');
- }
-
- if ($story->user_id !== $user->id && ! isAdmin()) {
- abort(403, 'Вы не являетесь автором данной записи!');
- }
-
- $files = $this->fileRepository->getFilesByStoryId($story->id);
-
- return $this->view->render(
- $response,
- 'stories/edit',
- compact('story', 'files')
- );
- }
-
- /**
- * Update
- *
- * @param int $id
- * @param Request $request
- * @param Response $response
- * @param Slug $slug
- *
- * @return Response
- */
- public function update(
- int $id,
- Request $request,
- Response $response,
- Slug $slug,
- ): Response
- {
- $user = getUser();
-
- $story = $this->storyRepository->getById($id);
- if (! $story) {
- abort(404, 'Статья не найдена!');
- }
-
- if ($story->user_id !== $user->id && ! isAdmin()) {
- abort(403, 'Вы не являетесь автором данной записи!');
- }
-
- $input = (array) $request->getParsedBody();
- $tags = array_map('sanitize', $input['tags'] ?? []);
-
- $this->validator
- ->required(['csrf', 'title', 'text', 'tags'])
- ->same('csrf', $this->session->get('csrf'), 'Неверный идентификатор сессии, повторите действие!')
- ->length('title', setting('story.title_min_length'), setting('story.title_max_length'))
- ->length('text', setting('story.text_min_length'), setting('story.text_max_length'))
- ->custom(count($tags) <= setting('story.tags_max'), ['tags' => 'Превышено максимальное количество тегов'])
- ->boolean('locked');
-
- foreach ($tags as $tag) {
- $this->validator->custom(
- Str::length($tag) >= setting('story.tags_min_length') && Str::length($tag) <= setting('story.tags_max_length'),
- ['tags' => sprintf('Длина тегов должна быть от %d до %d символов!', setting('story.tags_min_length'), setting('story.tags_max_length'))]
- );
- }
-
- Tag::query()->where('story_id', $story->id)->delete();
-
- foreach ($tags as $value) {
- Tag::query()->create([
- 'story_id' => $story->id,
- 'tag' => Str::lower($value),
- ]);
- }
-
- if ($this->validator->isValid($input)) {
- $slugify = $slug->slugify($input['title']);
-
- $story->update([
- 'title' => sanitize($input['title']),
- 'slug' => $slugify,
- 'text' => sanitize($input['text']),
- 'locked' => isAdmin() ? $input['locked'] ?? $story->locked : $story->locked,
- ]);
-
- $this->session->set('flash', ['success' => 'Статья успешно изменена!']);
-
- return $this->redirect($response, '/' . $slugify . '-' . $id);
- }
-
- $this->session->set('flash', ['errors' => $this->validator->getErrors(), 'old' => $input]);
-
- return $this->redirect($response, '/' . $id . '/edit');
- }
-
- /**
- * Destroy
- *
- * @param int $id
- * @param Request $request
- * @param Response $response
- *
- * @return Response
- */
- public function destroy(int $id, Request $request, Response $response): Response
- {
- $user = getUser();
-
- $story = $this->storyRepository->getById($id);
- if (! $story) {
- abort(404, 'Статья не найдена');
- }
-
- if ($story->user_id !== $user->id && ! isAdmin()) {
- abort(403, 'Вы не являетесь автором данной записи!');
- }
-
- $input = (array) $request->getParsedBody();
-
- $this->validator
- ->required('csrf')
- ->same('csrf', $this->session->get('csrf'), 'Неверный идентификатор сессии, повторите действие!');
-
- if ($this->validator->isValid($input)) {
- $story->delete();
-
- $this->session->set('flash', ['success' => 'Статья успешно удалена!']);
- } else {
- $this->session->set('flash', ['errors' => $this->validator->getErrors()]);
- }
-
- return $this->redirect($response, '/');
- }
- }