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
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 !== ''));
|
|
}
|
|
}
|