138 lines
4.3 KiB
PHP
138 lines
4.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace KupShop\FeedsBundle\Utils;
|
|
|
|
use KupShop\FeedsBundle\Dto\FeedItem;
|
|
use KupShop\FeedsBundle\Feed\IFeed;
|
|
|
|
class FeedRenderer
|
|
{
|
|
public function __construct(
|
|
private FeedUtils $feedUtils,
|
|
) {
|
|
}
|
|
|
|
public function render(IFeed $feed, array $feedRow, ?int $limit = null, string $format = 'xml'): void
|
|
{
|
|
// standard rendering of XML feed
|
|
if ($format == 'xml') {
|
|
$feed->render($feedRow, $limit);
|
|
|
|
return;
|
|
}
|
|
|
|
// we need generator that can be passed to formatter
|
|
$generator = function () use ($feed, $feedRow, $limit): \Generator {
|
|
foreach ($feed->renderWithGenerator($feedRow, $limit) as $key => $xmlItem) {
|
|
// ignoring XML root element, only inner items are passed to formatter
|
|
if (in_array($key, ['start', 'end'])) {
|
|
continue;
|
|
}
|
|
|
|
foreach ($this->getXMLAsArray($xmlItem) as $item) {
|
|
yield $item;
|
|
}
|
|
}
|
|
};
|
|
|
|
$formatter = $this->feedUtils->getFeedFormatter($format);
|
|
$formatter->process(
|
|
$this->getConfiguration($feedRow),
|
|
$generator()
|
|
);
|
|
}
|
|
|
|
private function getConfiguration(array $feedRow): array
|
|
{
|
|
$template = json_decode($feedRow['template'] ?: '', true) ?: [];
|
|
|
|
$xml = new \SimpleXMLElement($template['beginning'].$template['end']);
|
|
|
|
$attributes = [];
|
|
foreach ($xml->attributes() as $key => $value) {
|
|
$attributes[$key] = (string) $value;
|
|
}
|
|
|
|
return $attributes;
|
|
}
|
|
|
|
/**
|
|
* @return FeedItem[]
|
|
*/
|
|
private function getXMLAsArray(string $xml): array
|
|
{
|
|
$reader = new \XMLReader();
|
|
$reader->xml("<root>{$xml}</root>");
|
|
|
|
// move to the first non-root element
|
|
while (($reader->nodeType !== \XMLReader::ELEMENT || $reader->name === 'root') && $reader->read()) {
|
|
}
|
|
|
|
$elementName = $reader->name;
|
|
|
|
$result = [];
|
|
// iterate each element inside of root element and convert it to array
|
|
do {
|
|
if ($reader->nodeType === \XMLReader::ELEMENT && $reader->name === $elementName) {
|
|
$result[] = new FeedItem($this->parseXMLNode($reader));
|
|
}
|
|
} while ($reader->read());
|
|
|
|
$reader->close();
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function parseXMLNode(\XMLReader $reader): array|string|null
|
|
{
|
|
$data = [];
|
|
|
|
$currentElement = $reader->name;
|
|
|
|
while ($reader->read()) {
|
|
if ($reader->nodeType == \XMLReader::ELEMENT) {
|
|
$key = $reader->name;
|
|
|
|
// Extract attributes
|
|
$attributes = [];
|
|
if ($reader->hasAttributes) {
|
|
while ($reader->moveToNextAttribute()) {
|
|
$attributes[$reader->name] = $reader->value;
|
|
}
|
|
$reader->moveToElement(); // Move back to the element
|
|
}
|
|
|
|
if (!$reader->isEmptyElement) {
|
|
// recursively process the child node
|
|
$value = $this->parseXMLNode($reader);
|
|
} else {
|
|
$value = null; // handle empty elements
|
|
}
|
|
|
|
$elementData = ['@value' => $value];
|
|
if (!empty($attributes)) {
|
|
$elementData['@attributes'] = $attributes;
|
|
}
|
|
|
|
// assign to the data array
|
|
if (isset($data[$key])) {
|
|
if (!is_array($data[$key]) || array_keys($data[$key]) !== range(0, count($data[$key]) - 1)) {
|
|
$data[$key] = [$data[$key]]; // Convert to array if not already
|
|
}
|
|
$data[$key][] = $elementData;
|
|
} else {
|
|
$data[$key] = $elementData;
|
|
}
|
|
} elseif ($reader->nodeType == \XMLReader::TEXT || $reader->nodeType == \XMLReader::CDATA) {
|
|
return htmlspecialchars_decode($reader->value, ENT_QUOTES);
|
|
} elseif ($reader->nodeType == \XMLReader::END_ELEMENT && $reader->name == $currentElement) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return empty($data) ? null : $data;
|
|
}
|
|
}
|