<?php
namespace JanusHercules\ContentDistributionFeedCreation\Domain\Entity;
use App\Entity\ContentDistribution\ContentDistributorFeed;
use App\Entity\RecurrentJob;
use App\Utility\DatabaseIdGenerator;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Column;
use JanusHercules\HighVolumeProcess\Domain\Entity\HighVolumeProcessTask;
use JanusHercules\HighVolumeProcess\Domain\Entity\HighVolumeProcessTaskResultInterface;
use ValueError;
#[ORM\Entity]
#[ORM\Table(name: 'work_on_recurrent_job_results')]
class WorkOnRecurrentJobResult implements HighVolumeProcessTaskResultInterface
{
public const MAX_XML_SECTION_LENGTH = 65536;
#[ORM\Id]
#[ORM\GeneratedValue(strategy: 'CUSTOM')]
#[ORM\CustomIdGenerator(class: DatabaseIdGenerator::class)]
#[Column(
type : Types::GUID,
unique: true
)]
private ?string $id = null;
public function getId(): ?string
{
return $this->id;
}
#[ORM\ManyToOne(targetEntity: RecurrentJob::class)]
#[ORM\JoinColumn(
name : 'recurrent_jobs_id',
referencedColumnName: 'id',
nullable : false,
onDelete : 'CASCADE'
)]
private RecurrentJob $recurrentJob;
public function getRecurrentJob(): RecurrentJob
{
return $this->recurrentJob;
}
public function setRecurrentJob(RecurrentJob $recurrentJob): void
{
$this->recurrentJob = $recurrentJob;
}
#[Column(
type: Types::TEXT,
)]
private string $xmlSection;
public function getXMLSection(): string
{
return $this->xmlSection;
}
public function setXMLSection(string $xmlSection): void
{
if (mb_strlen($xmlSection) > self::MAX_XML_SECTION_LENGTH) {
throw new ValueError('The XML section cannot exceed ' . self::MAX_XML_SECTION_LENGTH . ' characters.');
}
// Ensure proper UTF-8 handling for regex
mb_regex_encoding('UTF-8');
// Extract first XML tag - using /u modifier for UTF-8 support
if (!preg_match('/<([a-zA-Z][a-zA-Z0-9_:-]*)[^>]*>/u', $xmlSection, $openingTagMatch)) {
throw new ValueError('Invalid XML: No opening tag found.');
}
$tagName = $openingTagMatch[1];
// Check if it properly closes - using mb_ereg_replace for multibyte safety
$expectedClosingTag = "</{$tagName}>";
$trimmedXml = mb_ereg_replace('^\s+|\s+$', '', $xmlSection);
if (!is_string($trimmedXml) || !str_ends_with($trimmedXml, $expectedClosingTag)) {
throw new ValueError("Invalid XML: Opening tag <{$tagName}> does not have a matching closing tag.");
}
$this->xmlSection = $xmlSection;
}
#[ORM\ManyToOne(
targetEntity: HighVolumeProcessTask::class,
)]
#[ORM\JoinColumn(
name : 'high_volume_process_tasks_id',
referencedColumnName: 'id',
nullable : false,
onDelete : 'CASCADE'
)]
private HighVolumeProcessTask $task;
public function getTask(): HighVolumeProcessTask
{
return $this->task;
}
public function setTask(HighVolumeProcessTask $task): void
{
$this->task = $task;
}
#[ORM\ManyToOne(targetEntity: ContentDistributorFeed::class)]
#[ORM\JoinColumn(
name : 'content_distributor_feeds_id',
referencedColumnName: 'id',
nullable : false,
onDelete : 'CASCADE'
)]
private ContentDistributorFeed $contentDistributorFeed;
public function getContentDistributorFeed(): ContentDistributorFeed
{
return $this->contentDistributorFeed;
}
public function setContentDistributorFeed(ContentDistributorFeed $contentDistributorFeed): void
{
$this->contentDistributorFeed = $contentDistributorFeed;
}
}