菜单 小浣熊cms漫画模板网

多线程入库api

<?php
namespace apppicontroller;

use appmodelAuthor;
use appmodelBook;
use appmodelPhoto;
use OvertruePinyinPinyin;
use thinkController;
use thinkacadeDb;
use thinkRequest;
use appmodelChapter;
use appmodelTags;
use thinkException;

class Postbot
{
    public function save(Request $request)
    {
        try {
            if (!$request->isPost()) {
                throw new Exception('非法请求', 1);
            }

            $data = $request->param();
            $this->validateRequest($data);

            Db::startTrans();
            
            // 处理作者和书籍
            $author = $this->handleAuthor($data);
            $book = $this->handleBook($data, $author);
            
            // 处理章节
            $chapter = $this->handleChapter($data, $book);
            
            // 处理图片和标签
            $this->handlePhotos($chapter->id, $data['images']);
            $this->processTags($data['tags'], $book->id);
            
            Db::commit();
            
            return json(['code' => 0, 'message' => '发布成功']);
            
        } catch (Exception $e) {
            Db::rollback();
            $message = $e->getCode() === 0 ? '章节已存在' : $e->getMessage();
            return json(['code' => $e->getCode() ?: 1, 'message' => $message]);
        }
    }

    private function validateRequest($data)
    {
        if (!isset($data['api_key']) || $data['api_key'] != config('site.api_key')) {
            throw new Exception('Api密钥为空/密钥错误', 1);
        }
        
        $required = ['book_name', 'author', 'chapter_name', 'images'];
        foreach ($required as $field) {
            if (empty($data[$field])) {
                throw new Exception("缺少必要参数: {$field}", 1);
            }
        }
    }

    private function handleAuthor($data)
    {
        $authorName = trim($data['author']);
        $author = Author::where('author_name', $authorName)
            ->lock(true)
            ->find();

        if (!$author) {
            $author = new Author();
            $author->username = 'author_'.gen_uid(8);
            $author->password = gen_uid(12);
            $author->email = 'author_'.gen_uid(6).'@auto.com';
            $author->status = 1;
            $author->author_name = $authorName;
            
            try {
                $author->save();
            } catch (Exception $e) {
                if ($this->isDuplicateEntry($e)) {
                    return Author::where('author_name', $authorName)
                        ->lock(true)
                        ->find();
                }
                throw $e;
            }
        }
        
        return $author;
    }

    private function handleBook($data, $author)
    {
        $bookName = trim($data['book_name']);
        $book = Book::where('book_name', $bookName)
            ->lock(true)
            ->find();

        if (!$book) {
            $book = new Book();
            $this->populateBookData($book, $data, $author);
            
            try {
                $book->save();
            } catch (Exception $e) {
                if ($this->isDuplicateEntry($e)) {
                    return Book::where('book_name', $bookName)
                        ->lock(true)
                        ->find();
                }
                throw $e;
            }
        }
        
        return $book;
    }

    private function populateBookData($book, $data, $author)
    {
        $pinyin = new Pinyin();
        $book->unique_id = $pinyin->abbr($data['book_name']).'_'.md5(microtime(true).mt_rand(1000,9999));
        $book->author_id = $author->id;
        $book->author_name = $author->author_name;
        $book->area_id = (int)($data['area_id'] ?? 6);
        $book->book_name = trim($data['book_name']);
        $book->nick_name = trim($data['nick_name'] ?? '');
        $book->tags = trim($data['tags']);
        $book->src_url = trim($data['src_url']);
        $book->end = (int)($data['end'] ?? 1);
        $book->start_pay = 9999;
        $book->money = 0;
        $book->cover_url = filter_var($data['cover_url'], FILTER_VALIDATE_URL);
        $book->banner_url = filter_var($data['banner_url'], FILTER_VALIDATE_URL);
        $book->summary = mb_substr(trim($data['summary']), 0, 500);
        $book->last_time = time();
    }

    private function handleChapter($data, $book)
    {
        // 使用行锁检查章节
        $chapter = Chapter::where([
                'book_id' => $book->id,
                'chapter_name' => trim($data['chapter_name'])
            ])
            ->lock(true)
            ->find();

        if ($chapter) {
            throw new Exception('章节已存在', 0);
        }

        $chapter = new Chapter();
        $chapter->book_id = $book->id;
        $chapter->chapter_name = trim($data['chapter_name']);
        $chapter->chapter_order = (int)($data['chapter_order'] ?? 1);
        $chapter->create_time = time();
        $chapter->update_time = time();
        $chapter->save();

        // 更新书籍最后章节(带行锁)
        $this->updateLastChapter($book, $chapter);
        
        return $chapter;
    }

    private function updateLastChapter($book, $chapter)
    {
        $freshBook = Book::where('id', $book->id)
            ->lock(true)
            ->find();
            
        $freshBook->last_time = time();
        $freshBook->last_chapter_id = $chapter->id;
        $freshBook->last_chapter = $chapter->chapter_name;
        $freshBook->save();
    }

    private function handlePhotos($chapterId, $images)
    {
        $images = array_filter(explode(',', $images));
        foreach ($images as $index => $url) {
            $photo = new Photo();
            $photo->chapter_id = $chapterId;
            $photo->pic_order = $index;
            $photo->img_url = filter_var(trim($url), FILTER_VALIDATE_URL);
            $photo->save();
        }
    }

    private function processTags($tags, $bookId)
    {
        $tags = array_unique(explode('|', trim($tags)));
        foreach ($tags as $tagName) {
            if (!empty($tagName)) {
                $this->saveTag($tagName);
            }
        }
    }

    private function saveTag($tagName)
    {
        // 修正后的标签处理方法
        $tag = Tags::where('tag_name', trim($tagName))->find();
        if (!$tag) {
            $tag = new Tags();
            $tag->tag_name = trim($tagName);
            $tag->cover_url = config('app.default_tag_cover');
            $tag->create_time = time();
            $tag->update_time = time();
            $tag->save();
        }
    }

    private function isDuplicateEntry(Exception $e)
    {
        return strpos($e->getMessage(), 'Duplicate entry') !== false;
    }
}
1、测试重复章节提交应返回:
{"code":0,"message":"章节已存在"}
2、新章节提交应返回:
{"code":0,"message":"发布成功"}
3、参数缺失时应返回:
{"code":1,"message":"缺少必要参数: xxx"}