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" .
"\n\t\t" .
htmlspecialchars($url) .
"\n\t\t" .
$updatedAt .
"\n\t\tweekly\n\t\t1.00\n\t\n";
$this->currentXml .= $line;
$this->currentLineCount++;
}
protected function save(string $fileName)
{
$this->currentXml .= "\n";
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 =
'' .
"\n" .
'' .
"\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 =
'' .
"\n" .
'' .
"\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\n" .
"\t\t$url\n" .
"\t\t{$this->formatDate()}\n" .
"\t\n";
}
}
$string .= "\t\n\t\t{$baseUrl}/static-urls-sitemap.xml\n\t\t{$this->formatDate()}\n\t\n";
$string .= '';
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;
}
}