Proje dosyaları eklendi

This commit is contained in:
2026-08-29 15:53:53 +03:00
commit d3313400ca
440 changed files with 24827 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
<?php
namespace App\Services;
use App\Enums\KeywordStatus;
use App\Enums\ProjectStatus;
use App\Enums\SerpCheckStatus;
use App\Jobs\RunSerpCheck;
use App\Jobs\SubmitSerpCheck;
use App\Models\Keyword;
use App\Models\SerpCheck;
use App\Models\User;
use App\Serp\Data\SerpQuery;
use App\Serp\Operations\ActivationManager;
use App\Serp\SerpProviderRegistry;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
final class SerpCheckCreator
{
public function __construct(private SerpProviderRegistry $providers, private ActivationManager $activation) {}
public function create(User $user, Keyword $keyword, bool $dispatch = true, string $origin = 'manual'): SerpCheck
{
$keyword->refresh()->loadMissing('project');
if ($keyword->project->user_id !== $user->id || $keyword->status !== KeywordStatus::Active || $keyword->archived_at !== null || $keyword->project->status !== ProjectStatus::Active || $keyword->project->archived_at !== null) {
throw ValidationException::withMessages(['serp' => 'Bu anahtar kelime için kontrol başlatılamaz.']);
}if (! config('serp.enabled')) {
throw ValidationException::withMessages(['serp' => 'SERP kontrol hizmeti henüz yapılandırılmamış.']);
}$provider = $this->providers->resolve();
if ($provider->key() === 'dataforseo' && ! $this->activation->allowsNormal()) {
throw ValidationException::withMessages(['serp' => 'SERP kontrol hizmeti şu anda kullanılamıyor.']);
}$query = new SerpQuery($keyword->phrase, $keyword->search_engine->value, $keyword->country_code, $keyword->language_code, $keyword->device->value, 10);
if (! $provider->supports($query)) {
throw ValidationException::withMessages(['serp' => 'Seçili hedef yapılandırılmış sağlayıcı tarafından desteklenmiyor.']);
}if (! in_array($origin, ['manual', 'scheduled'], true)) {
throw ValidationException::withMessages(['serp' => 'Geçersiz kontrol kaynağı.']);
}$mode = $provider->key() === 'dataforseo' ? ($origin === 'manual' ? (string) config('serp.manual_mode') : (string) config('serp.automatic_mode')) : 'live';
if (! in_array($mode, ['live', 'standard'], true)) {
throw ValidationException::withMessages(['serp' => 'Geçersiz yürütme modu.']);
}
return Cache::lock('serp-create:'.$keyword->id, 10)->block(3, function () use ($user, $keyword, $dispatch, $origin, $mode) {
if ($keyword->serpChecks()->whereIn('status', ['pending', 'running'])->exists()) {
throw ValidationException::withMessages(['serp' => 'Bu anahtar kelime için devam eden bir kontrol var.']);
}$cool = (int) config('serp.keyword_cooldown_minutes');
if ($keyword->serpChecks()->where('created_at', '>', now()->subMinutes($cool))->exists()) {
throw ValidationException::withMessages(['serp' => 'Yeni kontrol için bekleme süresi henüz dolmadı.']);
}$used = SerpCheck::whereHas('keyword.project', fn ($q) => $q->where('user_id', $user->id))->where('created_at', '>=', now()->startOfDay())->count();
if ($used >= (int) config('serp.daily_user_quota')) {
throw ValidationException::withMessages(['serp' => 'Günlük SERP kontrol kotanıza ulaştınız.']);
}$check = DB::transaction(fn () => $keyword->serpChecks()->create(['phrase' => $keyword->phrase, 'status' => SerpCheckStatus::Pending, 'active_slot' => 'active', 'search_engine' => $keyword->search_engine, 'country_code' => $keyword->country_code, 'language_code' => $keyword->language_code, 'device' => $keyword->device, 'provider' => config('serp.provider'), 'execution_mode' => $mode, 'origin' => $origin, 'result_count' => 0]));
if ($dispatch) {
$job = $mode === 'standard' ? new SubmitSerpCheck($check->ulid) : new RunSerpCheck($check->ulid);
dispatch($job->onQueue(config('serp.queue')))->afterCommit();
}
return $check;
});
}
}