trypost/app/Http/Resources/App/Automation/FeedInspectionResource.php
Paulo Castellano 246a159f34 feat(automations): multi-format RSS/Atom feeds with dynamic variables
Replace the RSS-2.0-only SimpleXML parser with SimplePie so the Fetch RSS
node reads Atom 1.0 (YouTube, GitHub, The Verge…) and RSS 2.0 + namespace
extensions (dc:, content:, media:, yt:, itunes:). Each item exposes stable
cross-format aliases (title, link, date, content, author, …) plus every
namespaced field flattened for use as {{ fetched.* }}.

Add a feed-inspection endpoint that discovers a feed's real fields and feeds
them into the editor's expression autocomplete. Allow {{ }} expressions in the
feed URL via a ResolvableUrl rule. Parsing moves to a dedicated FeedParser
service; the fetch keeps the SSRF guard and gains XXE-safe parsing.
2026-06-16 10:56:08 -03:00

69 lines
1.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Resources\App\Automation;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
/**
* Flattens the first parsed feed item into a catalog of `{{ fetched.* }}` paths
* with sample values, so the editor can offer them as expression completions.
*
* @property array<string, mixed> $resource The first normalized feed item.
*/
class FeedInspectionResource extends JsonResource
{
private const SAMPLE_MAX_LENGTH = 120;
/**
* @return array{fields: list<array{path: string, sample: string}>}
*/
public function toArray(Request $request): array
{
return [
'fields' => $this->flatten((array) $this->resource),
];
}
/**
* @param array<string, mixed> $item
* @return list<array{path: string, sample: string}>
*/
private function flatten(array $item, string $prefix = 'fetched'): array
{
$fields = [];
foreach ($item as $key => $value) {
$path = "{$prefix}.{$key}";
if (is_array($value) && $this->isAssoc($value)) {
$fields = array_merge($fields, $this->flatten($value, $path));
continue;
}
$fields[] = ['path' => $path, 'sample' => $this->sample($value)];
}
return $fields;
}
/**
* @param array<int|string, mixed> $value
*/
private function isAssoc(array $value): bool
{
return $value !== [] && ! array_is_list($value);
}
private function sample(mixed $value): string
{
$text = is_array($value)
? (json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?: '')
: (string) $value;
return str($text)->squish()->limit(self::SAMPLE_MAX_LENGTH)->value();
}
}