开发 为 laravel 构建 Sitemap 和 RSS

· 发布于 5个月前 · 223 次阅读

Sitemap

先说 Sitemap 的构建, 你需要先了解一下 Sitemap 协议。

git 上找到一个库 laravel-sitemap.

其提供了几个简单的 api 用于构建 Sitemap.

  1. 添加 url add($loc, $lastmod = null, $priority = null, $freq = null, $images = [], $title = null, $translations = [], $videos = [], $googlenews = [], $alternates = []): void

  2. 添加 sitemap 用于构建 sitemap-index addSitemap($loc, $lastmod = null): void

  3. 视图渲染,动态渲染 render($format = 'xml', $style = null): View

  4. 生成静态文件 store($format = 'xml', $filename = 'sitemap', $path = null, $style = null): void

<?php

namespace App\Tools;

use App\Models\Category;
use App\Models\Option;
use App\Models\Post;
use Laravelium\Sitemap;
use Illuminate\Support\Carbon;

final class SitemapService
{
    /**
     * @var Sitemap
     */
    private $sitemap;

    public function __construct()
    {
        $this->sitemap = resolve(Sitemap::class);
    }

    public function buildPages()
    {
        $option = Option::where('name', 'last_updated_at')->first();
        if (!is_null($option)) {
            $last_updated_at = Carbon::parse($option->value)->tz('UTC')->toAtomString();
        } else {
            $last_updated_at = Carbon::now()->tz('UTC')->toAtomString();
        }

        $this->sitemap->add(
            config('app.url'),
            $last_updated_at,
            '1.0',
            'always'
        );

        foreach (['topics', 'articles'] as $name) {
            $this->sitemap->add(
                url($name),
                $last_updated_at,
                '0.9',
                'daily'
            );
        }

        $pages = Post::reviewed()->pages()
            ->select(['id', 'slug', 'created_at', 'updated_at'])
            ->get();

        foreach ($pages as $page) {
            $this->sitemap->add(
                route('page', ['slug' => $page->slug]),
                $page->updated_at->tz('UTC')->toAtomString(),
                '0.5',
                'monthly'
            );
        }

        $this->buildSitemap('pages');
    }

    public function buildArticles()
    {
        $counter = 0;
        $sitemapCounter = 0;

        Post::reviewed()->articles()
            ->select(['id', 'created_at', 'updated_at'])
            ->chunk(100, function ($articles) use (&$counter, &$sitemapCounter) {
                foreach ($articles as $article) {
                    if ($counter == 10000) {
                        $this->buildSitemap('articles', $sitemapCounter);
                        // reset the counter
                        $counter = 0;
                        // count generated sitemap
                        $sitemapCounter++;
                    }

                    // add product to items array
                    $this->sitemap->add(
                        route('articles.show', ['article' => $article]),
                        $article->updated_at->tz('UTC')->toAtomString(),
                        '0.8',
                        'weekly');
                    // count number of elements
                    $counter++;
                }
            });

        // you need to check for unused items
        if (!empty($this->sitemap->model->getItems())) {
            $this->buildSitemap('articles', $sitemapCounter);
        }
    }

    public function buildTopics()
    {
        $counter = 0;
        $sitemapCounter = 0;

        Post::reviewed()->topics()
            ->select(['id', 'created_at', 'updated_at'])
            ->chunk(100, function ($topics) use (&$counter, &$sitemapCounter) {
                foreach ($topics as $topic) {
                    if ($counter == 10000) {
                        $this->buildSitemap('topics', $sitemapCounter);
                        // reset the counter
                        $counter = 0;
                        // count generated sitemap
                        $sitemapCounter++;
                    }

                    // add product to items array
                    $this->sitemap->add(
                        route('topics.show', ['article' => $topic]),
                        $topic->updated_at->tz('UTC')->toAtomString(),
                        '0.8',
                        'weekly');
                    // count number of elements
                    $counter++;
                }
            });

        // you need to check for unused items
        if (!empty($this->sitemap->model->getItems())) {
            $this->buildSitemap('topics', $sitemapCounter);
        }
    }

    public function buildCategories()
    {
        $postCategories = Category::postType()->where('objects_num', '>', 0)
            ->select(['id', 'created_at', 'updated_at'])
            ->get();

        foreach ($postCategories as $category) {
            $this->sitemap->add(
                route('categories.show', ['category' => $category]),
                $category->updated_at->tz('UTC')->toAtomString(),
                '0.5',
                'weekly');
        }

        $this->buildSitemap('categories');
    }

    public function buildIndex()
    {
        // generate new sitemapindex that will contain all generated sitemaps above
        $this->sitemap->store('sitemapindex', 'sitemap');
    }

    private function buildSitemap($type, $sitemapCounter = null)
    {
        $filename = "sitemaps/sitemap-{$type}";

        if (!is_null($sitemapCounter)) {
            $filename .= "-{$sitemapCounter}";
        }

        // generate sitemap with last items
        $this->sitemap->store('xml', $filename);

        \Log::info(Carbon::now() . " - 生成了 {$filename}");

        // add sitemap to sitemaps array
        $this->sitemap->addSitemap(url("{$filename}.xml"));

        // reset items array
        $this->sitemap->model->resetItems();
    }
}

RSS

同样在 github 找到一个开源库 laravel-rss

其提供的接口也比较简单

public function setEncode($encode); //默认UTF-8

public function channel(array $channel);

public function item(array $item);

public function items(array $items);

public function build();

public function fastBuild(array $channel, array $item);

可以创建一个 RSS 控制器

<?php

namespace App\Http\Controllers;

use App\Repositories\AggregationRepository;
use Moell\Rss\Rss;
use Illuminate\Support\Carbon;
use Illuminate\Http\Request;

class RssController extends Controller
{
    protected $aggregationRepository;
    protected $rss;

    public function __construct(AggregationRepository $aggregationRepository)
    {
        $this->aggregationRepository = $aggregationRepository;
        $this->rss = resolve(Rss::class);
    }

    public function index()
    {
        $channel = [
            'title' => config('app.name'),
            'link' => config('app.url'),
            'description' => 'Your description',
            'language' => 'zh-Hans',
            'generator' => 'laravel',
            'category' => [
                'value' => 'html',
                'attr' => [
                    'domain' => config('app.url'),
                ]
            ]
        ];

        $rss = $this->rss->channel($channel);

        $this->aggregationRepository->query()
            ->orderBy('created_at', 'desc')
            ->take(config('zues.rssSize'))
            ->chunk(config('zues.perPage'), function ($posts) use (&$rss) {
                foreach ($posts as $post) {
                    $item = [
                        'title' => $post->name,
                        'link' => $post->url(),
                        'description' => $post->excerpt,
                        'category' => $post->category_name,
                        'pubDate' => Carbon::parse($post->created_at, 'Asia/Chongqing')->format('D, d M Y H:i:s O'),
                        'guid' => $url,
                    ];

                    $rss->item($item);
                }
            });

        return response($rss, 200, ['Content-Type' => 'text/xml']);
    }
}
共收到 0 条回复
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册