235 lines
6.7 KiB
PHP
Executable File
235 lines
6.7 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Common\Admin\Sitemap;
|
|
|
|
use Carbon\Carbon;
|
|
use Common\Core\Contracts\AppUrlGenerator;
|
|
use Common\Pages\CustomPage;
|
|
use File;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Str;
|
|
|
|
class BaseSitemapGenerator
|
|
{
|
|
|
|
protected int $queryChunkSize = 1000;
|
|
protected string $currentDateTimeString;
|
|
protected int $currentResourceSitemapCount = 0;
|
|
protected string | null $currentXml = null;
|
|
protected int $currentLineCount = 0;
|
|
|
|
public function __construct()
|
|
{
|
|
@ini_set('memory_limit', '160M');
|
|
@ini_set('max_execution_time', 7200);
|
|
$this->currentDateTimeString = Carbon::now()->toDateTimeString();
|
|
}
|
|
|
|
protected function getAppQueries(): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
protected function getAppStaticUrls(): array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
public function generate(): void
|
|
{
|
|
$index = [];
|
|
|
|
$queries = array_merge(
|
|
[
|
|
app(CustomPage::class)->select(['id', 'title', 'slug']),
|
|
],
|
|
$this->getAppQueries(),
|
|
);
|
|
|
|
foreach ($queries as $query) {
|
|
$resourceName = str_replace(
|
|
'_',
|
|
'-',
|
|
$query->getModel()->getTable(),
|
|
);
|
|
$index[$resourceName] = $this->createSitemapForResource(
|
|
$query,
|
|
$resourceName,
|
|
);
|
|
}
|
|
|
|
$this->makeStaticMap();
|
|
$this->makeIndex($index);
|
|
}
|
|
|
|
protected function createSitemapForResource(
|
|
Builder $model,
|
|
string $name
|
|
): int {
|
|
$model
|
|
->orderBy('id')
|
|
->chunk($this->queryChunkSize, function ($records) use ($name) {
|
|
$modelName = ucfirst(Str::snake($records->first()::MODEL_TYPE));
|
|
$methodName = "add{$modelName}Line";
|
|
foreach ($records as $record) {
|
|
// allow extending class to override line adding for specific model
|
|
if (method_exists($this, $methodName)) {
|
|
$this->$methodName(
|
|
$this->getModelUrl($record),
|
|
$this->getModelUpdatedAt($record),
|
|
$name,
|
|
);
|
|
} else {
|
|
$this->addNewLine(
|
|
$this->getModelUrl($record),
|
|
$this->getModelUpdatedAt($record),
|
|
$name,
|
|
);
|
|
}
|
|
}
|
|
});
|
|
|
|
if ($this->currentLineCount) {
|
|
$this->save("$name-sitemap-{$this->currentResourceSitemapCount}");
|
|
}
|
|
|
|
$numberOfSitemapsGenerated = $this->currentResourceSitemapCount;
|
|
|
|
$this->currentResourceSitemapCount = 0;
|
|
$this->currentLineCount = 0;
|
|
|
|
return $numberOfSitemapsGenerated;
|
|
}
|
|
|
|
protected function addNewLine(string $url, string $updatedAt, string $name)
|
|
{
|
|
if (!$this->currentXml) {
|
|
$this->startNewXmlFile();
|
|
}
|
|
|
|
if ($this->currentLineCount === 50000) {
|
|
$this->save("$name-sitemap-{$this->currentResourceSitemapCount}");
|
|
$this->startNewXmlFile();
|
|
}
|
|
|
|
$updatedAt = $this->formatDate($updatedAt);
|
|
|
|
$line =
|
|
"\t" .
|
|
"<url>\n\t\t<loc>" .
|
|
htmlspecialchars($url) .
|
|
"</loc>\n\t\t<lastmod>" .
|
|
$updatedAt .
|
|
"</lastmod>\n\t\t<changefreq>weekly</changefreq>\n\t\t<priority>1.00</priority>\n\t</url>\n";
|
|
|
|
$this->currentXml .= $line;
|
|
|
|
$this->currentLineCount++;
|
|
}
|
|
|
|
protected function save(string $fileName)
|
|
{
|
|
$this->currentXml .= "\n</urlset>";
|
|
|
|
File::ensureDirectoryExists(public_path('storage/sitemaps'));
|
|
File::put(
|
|
public_path("storage/sitemaps/$fileName.xml"),
|
|
$this->currentXml,
|
|
);
|
|
|
|
$this->currentXml = null;
|
|
$this->currentLineCount = 0;
|
|
$this->currentResourceSitemapCount++;
|
|
}
|
|
|
|
protected function startNewXmlFile()
|
|
{
|
|
$this->currentXml =
|
|
'<?xml version="1.0" encoding="UTF-8"?>' .
|
|
"\n" .
|
|
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">' .
|
|
"\n";
|
|
}
|
|
|
|
protected function makeStaticMap(): void
|
|
{
|
|
$urls = array_merge(
|
|
['', 'login', 'register', 'contact'],
|
|
$this->getAppStaticUrls(),
|
|
);
|
|
|
|
$urls = array_map(function ($data) {
|
|
if (is_string($data)) {
|
|
return [
|
|
'path' => $data,
|
|
'updated_at' => $this->currentDateTimeString,
|
|
];
|
|
} else {
|
|
return $data;
|
|
}
|
|
}, $urls);
|
|
|
|
foreach ($urls as $url) {
|
|
$this->addNewLine(
|
|
url($url['path']),
|
|
$url['updated_at'],
|
|
'static-urls',
|
|
);
|
|
}
|
|
|
|
$this->save('static-urls-sitemap');
|
|
}
|
|
|
|
protected function makeIndex(array $index): void
|
|
{
|
|
$baseUrl = url('storage/sitemaps');
|
|
|
|
$string =
|
|
'<?xml version="1.0" encoding="UTF-8"?>' .
|
|
"\n" .
|
|
'<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' .
|
|
"\n";
|
|
|
|
foreach ($index as $resourceName => $resourceSitemapCount) {
|
|
// sitemap count starts from 1
|
|
for ($i = 0; $i <= $resourceSitemapCount - 1; $i++) {
|
|
$url = "{$baseUrl}/{$resourceName}-sitemap-$i.xml";
|
|
$string .=
|
|
"\t<sitemap>\n" .
|
|
"\t\t<loc>$url</loc>\n" .
|
|
"\t\t<lastmod>{$this->formatDate()}</lastmod>\n" .
|
|
"\t</sitemap>\n";
|
|
}
|
|
}
|
|
|
|
$string .= "\t<sitemap>\n\t\t<loc>{$baseUrl}/static-urls-sitemap.xml</loc>\n\t\t<lastmod>{$this->formatDate()}</lastmod>\n\t</sitemap>\n";
|
|
|
|
$string .= '</sitemapindex>';
|
|
|
|
File::put(public_path('storage/sitemaps/sitemap-index.xml'), $string);
|
|
}
|
|
|
|
protected function getModelUrl(Model $model): string
|
|
{
|
|
$resourceName = Str::camel(class_basename($model));
|
|
return app(AppUrlGenerator::class)->$resourceName($model);
|
|
}
|
|
|
|
protected function formatDate(string $date = null): string
|
|
{
|
|
if (!$date) {
|
|
$date = $this->currentDateTimeString;
|
|
}
|
|
return date('Y-m-d\TH:i:sP', strtotime($date));
|
|
}
|
|
|
|
protected function getModelUpdatedAt(Model $model): string
|
|
{
|
|
return !$model->updated_at ||
|
|
$model->updated_at === '0000-00-00 00:00:00'
|
|
? $this->currentDateTimeString
|
|
: $model->updated_at;
|
|
}
|
|
}
|