title = $title; $feed->description = $description; $feed->link = $link; return $feed; } public function addItem(array $item): void { foreach (self::REQUIRED_PRODUCT_FIELDS as $field) { if (! isset($item[$field])) { throw new MissingRequiredFieldException("Required field '{$field}' is missing"); } } $this->products[] = $item; } public function toXml(): string { $data = [ 'rss' => [ '_attributes' => [ 'xmlns:g' => 'http://base.google.com/ns/1.0', 'version' => '2.0', ], 'channel' => [ 'title' => $this->title, 'description' => $this->description, 'link' => $this->link, ], ], ]; foreach ($this->products as $key => $product) { $data['rss']['channel']['item_' . $key] = $product; } $xml = ArrayToXml::convert($data, ''); $xml = str_replace([' ', '', '', "\n", "\r", 'remove'], '', $xml); // spatie/array-to-xml does not support repeated keys, so products are keyed as // item_0, item_1, etc. and renamed back to tags here. $xml = (string) preg_replace('/item_\d+/', 'item', $xml); return $xml; } public function generate(): Response { return ResponseFacade::make($this->toXml(), headers: ['Content-Type' => 'application/rss+xml']); } }