<?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin;
use App\Classes\Validator;
use App\Models\Article;
use App\Models\Blog;
use App\Models\Tag;
use App\Models\User;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Date;
use Illuminate\Support\Str;
use Illuminate\View\View;
class ArticleController extends AdminController
{
/**
* Главная страница
*/
public function index(): View
{
$categories = Blog::query()
->where('parent_id', 0)
->orderBy('sort')
->with('children', 'new', 'children.new', 'lastArticle.user')
->get();
$new = Article::query()
->active(false)
->where('draft', false)
->count();
return view('admin/blogs/index', compact('categories', 'new'));
}
/**
* Создание раздела
*/
public function create(Request $request, Validator $validator): RedirectResponse
{
if (! isAdmin(User::BOSS)) {
abort(403, __('errors.forbidden'));
}
$name = $request->input('name');
$validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
->length($name, setting('blog_category_min'), setting('blog_category_max'), ['name' => __('validator.text')]);
if ($validator->isValid()) {
$max = Blog::query()->max('sort') + 1;
$category = Blog::query()->create([
'name' => $name,
'sort' => $max,
]);
setFlash('success', __('blogs.category_success_created'));
return redirect()->route('admin.blogs.edit', ['id' => $category->id]);
}
setInput($request->all());
setFlash('danger', $validator->getErrors());
return redirect()->route('admin.blogs.index');
}
/**
* Редактирование раздела
*/
public function edit(int $id, Request $request, Validator $validator): View|RedirectResponse
{
if (! isAdmin(User::BOSS)) {
abort(403, __('errors.forbidden'));
}
$category = Blog::query()->with('children')->find($id);
if (! $category) {
abort(404, __('blogs.category_not_exist'));
}
$categories = $category->getChildren();
if ($request->isMethod('post')) {
$parent = int($request->input('parent'));
$name = $request->input('name');
$sort = int($request->input('sort'));
$closed = empty($request->input('closed')) ? 0 : 1;
$validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
->length($name, setting('blog_category_min'), setting('blog_category_max'), ['title' => __('validator.text')])
->notEqual($parent, $category->id, ['parent' => __('blogs.category_not_exist')]);
if ($validator->isValid()) {
$category->update([
'parent_id' => $parent,
'name' => $name,
'sort' => $sort,
'closed' => $closed,
]);
setFlash('success', __('blogs.category_success_edited'));
return redirect()->route('admin.blogs.index');
}
setInput($request->all());
setFlash('danger', $validator->getErrors());
}
return view('admin/blogs/edit', compact('categories', 'category'));
}
/**
* Удаление раздела
*/
public function delete(int $id, Request $request, Validator $validator): RedirectResponse
{
if (! isAdmin(User::BOSS)) {
abort(403, __('errors.forbidden'));
}
$category = Blog::query()->with('children')->find($id);
if (! $category) {
abort(404, __('blogs.category_not_exist'));
}
$validator->equal($request->input('_token'), csrf_token(), __('validator.token'))
->true($category->children->isEmpty(), __('blogs.category_has_subcategories'));
$article = Article::query()->where('category_id', $category->id)->exists();
if ($article) {
$validator->addError(__('blogs.articles_in_category'));
}
if ($validator->isValid()) {
$category->delete();
setFlash('success', __('blogs.category_success_deleted'));
} else {
setFlash('danger', $validator->getErrors());
}
return redirect()->route('admin.blogs.index');
}
/**
* Пересчет данных
*/
public function restatement(Request $request): RedirectResponse
{
if (! isAdmin(User::BOSS)) {
abort(403, __('errors.forbidden'));
}
if ($request->input('_token') === csrf_token()) {
restatement('blogs');
setFlash('success', __('main.success_recounted'));
} else {
setFlash('danger', __('validator.token'));
}
return redirect()->route('admin.blogs.index');
}
/**
* Список блогов
*/
public function blog(int $id): View
{
$category = Blog::query()->with('parent')->find($id);
if (! $category) {
abort(404, __('blogs.category_not_exist'));
}
$articles = Article::query()
->active()
->where('category_id', $id)
->orderByDesc('created_at')
->with('user')
->paginate(setting('blogpost'));
return view('admin/blogs/blog', compact('articles', 'category'));
}
/**
* Редактирование статьи
*/
public function editArticle(int $id, Request $request, Validator $validator): View|RedirectResponse
{
$article = Article::query()->find($id);
if (! $article) {
abort(404, __('blogs.article_not_exist'));
}
if ($request->isMethod('post')) {
$cid = int($request->input('cid'));
$title = $request->input('title');
$text = $request->input('text');
$tags = (array) $request->input('tags');
$tags = array_unique(array_diff($tags, ['']));
$published = $request->input('published');
$isDelay = (bool) $request->input('delay');
$isPublish = $request->input('action') === 'publish';
$category = Blog::query()->find($cid);
$validator
->equal($request->input('_token'), csrf_token(), __('validator.token'))
->length($title, setting('blog_title_min'), setting('blog_title_max'), ['title' => __('validator.text')])
->length($text, setting('blog_text_min'), setting('blog_text_max'), ['text' => __('validator.text')])
->notEmpty($category, ['cid' => __('blogs.category_not_exist')])
->between(count($tags), 1, 10, ['tags' => __('blogs.article_count_tags')]);
if ($isDelay && Date::parse($published) < now()) {
$validator->addError(['published' => __('blogs.article_delayed_time')]);
}
foreach ($tags as $tag) {
$validator->length($tag, setting('blog_tag_min'), setting('blog_tag_max'), ['tags' => __('blogs.article_error_tags')]);
}
if ($category) {
$validator->empty($category->closed, ['cid' => __('blogs.category_closed')]);
}
if ($validator->isValid()) {
$isDraft = $article->draft && ! $isPublish;
$isActive = ! $isDraft && ! $isDelay;
$article->update([
'category_id' => $category->id,
'title' => $title,
'text' => $text,
'draft' => $isDraft,
'active' => $isActive,
'published_at' => $isDelay ? $published : null,
]);
$tagIds = [];
foreach ($tags as $key => $tagName) {
$tag = Tag::query()->firstOrCreate(['name' => Str::lower($tagName)]);
$tagIds[$tag->id] = ['sort' => $key];
}
$article->tags()->sync($tagIds);
$flash = $isDraft ? __('blogs.article_success_edited') : __('blogs.article_success_created');
return redirect()
->route('articles.view', ['slug' => $article->slug])
->with('success', $flash);
}
setInput($request->all());
setFlash('danger', $validator->getErrors());
}
$categories = $article->category->getChildren();
return view('admin/blogs/edit_article', compact('article', 'categories'));
}
/**
* Удаление статьи
*/
public function deleteArticle(int $id, Request $request, Validator $validator): RedirectResponse
{
$page = int($request->input('page', 1));
$article = Article::query()->find($id);
if (! $article) {
abort(404, __('blogs.article_not_exist'));
}
$validator->equal($request->input('_token'), csrf_token(), __('validator.token'));
if ($validator->isValid()) {
$article->delete();
setFlash('success', __('blogs.article_success_deleted'));
} else {
setFlash('danger', $validator->getErrors());
}
return redirect()->route('admin.blogs.blog', ['id' => $article->category_id, 'page' => $page]);
}
/**
* Публикация статьи
*/
public function publish(int $id, Request $request): RedirectResponse
{
$article = Article::query()->find($id);
if (! $article) {
abort(404, __('blogs.article_not_exist'));
}
if ($request->input('_token') === csrf_token()) {
$active = $article->active ^ 1;
$article->update([
'active' => $active,
'draft' => false,
'created_at' => SITETIME,
]);
if ($active) {
$status = __('blogs.article_success_published');
$text = textNotice('article_publish', ['url' => route('articles.view', ['slug' => $article->slug], false), 'title' => $article->title]);
} else {
$status = __('blogs.article_success_unpublished');
$text = textNotice('article_unpublish', ['url' => route('articles.view', ['slug' => $article->slug], false), 'title' => $article->title]);
}
$article->user->sendMessage(null, $text);
$flash = ['success', $status];
} else {
$flash = ['danger', __('validator.token')];
}
return redirect()
->route('admin.articles.edit', ['id' => $article->id])
->with(...$flash);
}
/**
* Новые статьи
*/
public function new(): View
{
$articles = Article::query()
->active(false)
->where('draft', false)
->orderByDesc('created_at')
->with('user', 'category')
->paginate(setting('blogpost'));
return view('admin/blogs/new', compact('articles'));
}
}