File "ArticleService.php"
Full Path: /var/www/html/back/app/Domain/Article/ArticleService.php
File size: 6.72 KB
MIME-type: text/x-php
Charset: utf-8
<?php
declare(strict_types=1);
namespace App\Domain\Article\Services;
use App\BaseClasses\BaseService;
use App\Domain\Article\Requests\CreateArticleRequest;
use App\Domain\Article\Requests\GetArticleListRequest;
use App\Domain\Article\Requests\UpdateArticleRequest;
use App\Models\Article;
use App\Models\ArticleGroup;
use App\Models\Payment;
use App\Models\PaymentDistribution;
use App\Models\Project;
use App\Services\CashFlowService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\DB;
class ArticleService extends BaseService
{
public function __construct(protected CashFlowService $cashFlowService)
{
}
/**
* Получить все статьи.
*
* @return Builder
*/
public function getAll(int $modelID, ?GetArticleListRequest $request): Builder
{
$query = Article::query()
->where('model_id', $modelID)
->with([
'group',
'articleProjectLinks'
]);
if ($request->has('search')) {
$search = mb_convert_case($request->get('search'), MB_CASE_LOWER);
$query->whereRaw('LOWER(name) LIKE ?', ["%{$search}%"])
->orWhereHas('group', function ($q) use ($search, $modelID) {
$q->where('model_id', $modelID);
$q->whereRaw('LOWER(name) LIKE ?', ["%{$search}%"]);
});
}
if ($request->has('article_group_id')) {
$query->where('article_group_id', $request->get('article_group_id'));
}
if ($request->has('article_type')) {
$query->where('article_type', $request->get('article_type'));
}
if ($request->has('payment_id')) {
/** @var Payment $payment */
$payment = Payment::find($request->get('payment_id'));
$ids = [];
foreach ($payment->distributions as $distribution) {
$ids[] = $distribution->article->id;
}
$query->whereIn('id', $ids);
}
return $query;
}
/**
* Создать новую статью.
*
* @param CreateArticleRequest $request
* @return Article
*/
public function create(int $modelID, CreateArticleRequest $request): Article
{
return DB::transaction(function () use ($modelID, $request) {
if (!empty($request->article_group_id)) {
ArticleGroup::query()
->where('model_id', $modelID)
->where('id', $request->article_group_id)
->firstOrFail();
}
$article = Article::create(array_merge($request->toArray(), ['model_id' => $modelID]));
if ($request->sort) {
$this->cashFlowService->moveArticleOrArticleGroupInCashFlow($article->id, $request->sort, $request->article_group_id);
}
return $article;
});
}
/**
* Обновить существующую статью.
*
* @param int $id
* @param UpdateArticleRequest $request
* @return Article
* @throws ModelNotFoundException
*/
public function update(int $id, UpdateArticleRequest $request): Article
{
$article = $this->findById($id);
if (!empty($request->article_group_id)) {
ArticleGroup::query()
->where('model_id', $article->model_id)
->where('id', $request->article_group_id)->firstOrFail();
}
$article->update($request->toArray());
$article->fresh(['group']);
return $article;
}
/**
* Найти статью по ID.
*
* @param int $id
* @return Article
* @throws ModelNotFoundException
*/
public function findById(int $id): Article
{
return Article::query()
->with('group')
->with('projects')
->with('articleProjectLinks')
->findOrFail($id);
}
/**
* Платежи по статье.
*
*/
public function payments(int $id)
{
return PaymentDistribution::query()->where('article_id', $id)->sum('amount');
}
/**
* Удалить статью.
*
* @param int $id
* @param int|null|string $newArticleId
* @return bool
*/
public function delete(int $id, int|string $newArticleId = null): bool
{
return DB::transaction(function () use ($id, $newArticleId) {
$article = $this->findById($id);
if ($article->article_group_id) {
$this->cashFlowService->sortArticleInGroupAfterDelete($article->article_group_id, $article->sort);
} else {
$this->cashFlowService->sortArticleWithoutGroupAfterDelete($article->sort);
}
$projectIds = $article->paymentDistributions->each(function (PaymentDistribution $pd) use ($newArticleId): void {
$pd->update([
'article_id' => $newArticleId,
]);
})
->map(fn (PaymentDistribution $pd) => $pd->project_id)
->filter()->unique()->values();
if (!empty($projectIds)) {
$newArticle = $this->findById((int)$newArticleId);
$this->attachToProjects($newArticle, $projectIds);
}
return $article->delete();
});
}
public function setDefault(int $articleID, bool $isDefault): bool
{
$article = $this->findById($articleID);
if ($isDefault) {
$projects = $article->model->projects->pluck('id');
$this->attachToProjects($article, $projects);
} else {
$this->detachProjectsWithoutPayments($article);
}
return $article->update(['default_in_project' => $isDefault]);
}
private function attachToProjects(Article $article, iterable $projects): void
{
$projectIds = collect($projects)
->map(function (int|Project $project) {
return $project instanceof Project ? $project->id : $project;
})
->unique()
->values()
->all();
if (empty($projectIds)) {
return;
}
$article->projects()->syncWithoutDetaching($projectIds);
}
public function detachProjectsWithoutPayments(Article $article): void
{
$projectIds = $article->projects()
->whereDoesntHave('paymentDistributions', function ($query) use ($article) {
$query->where('article_id', $article->id);
})
->pluck('projects.id')
->all();
if ($projectIds !== []) {
$article->projects()->detach($projectIds);
}
}
}