68 lines
2.6 KiB
PHP
68 lines
2.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Opportunity;
|
|
use App\Support\PublicSitemapXml;
|
|
use Generator;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
class PublicSitemapController extends Controller
|
|
{
|
|
private const PAGE_SIZE = 1000;
|
|
|
|
public function index(PublicSitemapXml $xml): StreamedResponse
|
|
{
|
|
$base = $this->base();
|
|
$pages = (int) ceil(Opportunity::published()->count() / self::PAGE_SIZE);
|
|
$locations = (static function () use ($base, $pages): Generator {
|
|
yield $base.'/sitemap/pages.xml';
|
|
for ($page = 1; $page <= $pages; $page++) {
|
|
yield $base.'/sitemap/opportunities/'.$page.'.xml';
|
|
}
|
|
})();
|
|
|
|
return $this->response($xml, $locations, true);
|
|
}
|
|
|
|
public function pages(PublicSitemapXml $xml): StreamedResponse
|
|
{
|
|
$base = $this->base();
|
|
$paths = ['/', '/oportunidades', '/sectores', '/como-investir', '/documentos', '/apoio', '/simulador-fiscal', '/politica-de-privacidade', '/termos-de-uso'];
|
|
|
|
return $this->response($xml, array_map(fn ($path) => $base.$path, $paths));
|
|
}
|
|
|
|
public function opportunities(string $page, PublicSitemapXml $xml): StreamedResponse
|
|
{
|
|
$number = filter_var($page, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'max_range' => 1000000]]);
|
|
abort_if($number === false, 404);
|
|
$base = $this->base();
|
|
$records = Opportunity::published()->orderBy('id')->offset(($number - 1) * self::PAGE_SIZE)->limit(self::PAGE_SIZE)->get(['slug']);
|
|
abort_if($records->isEmpty(), 404);
|
|
|
|
return $this->response($xml, $records->map(fn ($record) => $base.'/oportunidades/'.rawurlencode($record->slug)));
|
|
}
|
|
|
|
private function base(): string
|
|
{
|
|
$url = rtrim((string) config('app.url'), '/');
|
|
$parts = parse_url($url);
|
|
abort_unless(filter_var($url, FILTER_VALIDATE_URL) && is_array($parts)
|
|
&& in_array($parts['scheme'] ?? null, ['http', 'https'], true)
|
|
&& ! isset($parts['query']) && ! isset($parts['fragment']) && ! isset($parts['user']) && ! isset($parts['pass']), 503);
|
|
|
|
return $url;
|
|
}
|
|
|
|
/** @param iterable<string> $locations */
|
|
private function response(PublicSitemapXml $xml, iterable $locations, bool $index = false): StreamedResponse
|
|
{
|
|
return response()->stream(static function () use ($xml, $locations, $index): void {
|
|
foreach ($xml->chunks($locations, $index) as $chunk) {
|
|
echo $chunk;
|
|
}
|
|
}, 200, ['Content-Type' => 'application/xml; charset=UTF-8', 'Cache-Control' => 'no-store', 'X-Content-Type-Options' => 'nosniff']);
|
|
}
|
|
}
|