You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

76 lines
3.2 KiB

<?php
namespace App\Services\CompanyNews;
use App\Models\CompanyNews;
use Carbon\Carbon;
use InvalidArgumentException;
class NewsImporter
{
public function store(object $task, array $item): bool
{
$title = $this->text($item, 'Title');
if ($title === '') {
throw new InvalidArgumentException('新闻缺少标题');
}
$newsId = $this->text($item, 'NewsId');
$id = $this->text($item, 'Id');
$url = $this->text($item, 'Url');
$identity = $newsId !== '' ? 'news:'.$newsId : ($id !== '' ? 'id:'.$id : 'url:'.$url);
if ($newsId === '' && $id === '' && $url === '') {
throw new InvalidArgumentException('新闻缺少 NewsId、Id 和原文链接,无法去重');
}
foreach (['NewsId' => 255, 'Id' => 255, 'Source' => 255, 'EmotionType' => 50] as $field => $max) {
if (mb_strlen($this->text($item, $field)) > $max) {
throw new InvalidArgumentException($field.' 字段过长');
}
}
$published = $this->text($item, 'PublishTime');
if ($published !== '' && !Carbon::hasFormat($published, 'Y-m-d H:i:s')) {
throw new InvalidArgumentException('新闻发布时间格式不正确');
}
$codes = $this->parts($this->text($item, 'Category'));
$names = $this->parts($this->text($item, 'CategoryDesc'));
$categories = [];
foreach ($codes as $i => $code) {
$categories[] = ['code' => $code, 'name' => $names[$i] ?? ''];
}
$news = CompanyNews::firstOrNew([
'company_id' => $task->company_id, 'provider' => 'yuanhe-qcc',
'dedup_key' => hash('sha256', $identity),
]);
$new = !$news->exists;
if ($new) {
$news->fill([
'company_name_snapshot' => $task->company_name, 'title' => $title,
'first_seen_at' => now(), 'first_task_id' => $task->id,
'review_status' => 'pending', 'is_visible' => false,
]);
}
// Never write editorial fields, review decisions or visibility on a repeated import.
$news->fill([
'external_id' => $id ?: null, 'external_news_id' => $newsId ?: null,
'source_title' => $title, 'source_name' => $this->text($item, 'Source'),
'source_url' => $url, 'source_content' => $this->text($item, 'Content'),
'source_published_at' => $published ?: null,
'news_tags' => $this->parts($this->text($item, 'NewsTags')),
'categories' => $categories, 'emotion_type' => $this->text($item, 'EmotionType'),
'raw_payload' => $item, 'last_seen_at' => now(), 'last_task_id' => $task->id,
])->save();
return $new;
}
private function text(array $item, string $key): string
{
if (isset($item[$key]) && !is_scalar($item[$key])) {
throw new InvalidArgumentException($key.' 字段格式不正确');
}
return trim((string) ($item[$key] ?? ''));
}
private function parts(string $text): array
{
return array_values(array_filter(array_map('trim', explode(',', $text)), fn ($v) => $v !== ''));
}
}