Completed
Push — master ( 5686d5...6d274d )
by Jakub
06:36
created

Generator::getDataSource()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 2
ccs 0
cts 1
cp 0
crap 2
rs 10
1
<?php
2
declare(strict_types=1);
3
4
namespace Nexendrie\Rss;
5
6
use Nexendrie\Rss\Extensions\RssCore;
7
use Symfony\Component\OptionsResolver\OptionsResolver;
8
use Nette\Utils\Arrays;
9
10
/**
11
 * RSS Channel Generator
12
 *
13
 * @author Jakub Konečný
14
 * @property callable|null $dataSource
15
 * @property string $template
16
 * @method void onBeforeGenerate(Generator $generator, array $info)
17
 * @method void onAddItem(Generator $generator, \SimpleXMLElement $channel, RssChannelItem $itemDefinition, \SimpleXMLElement $item)
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 132 characters
Loading history...
18
 * @method void onAfterGenerate(Generator $generator, array $info)
19
 */
20 1
final class Generator {
21
  use \Nette\SmartObject;
22
23
  private const NAMESPACE_ATTRIBUTE_HACK = "__extension_namespace__";
24
25
  public string $dateTimeFormat = "r";
26
  /** @var callable|null */
27
  private $dataSource = null;
28
  public int $shortenDescription = 150;
29
  public string $generator = "Nexendrie RSS";
30
  public string $docs = "http://www.rssboard.org/rss-specification";
31
  private string $template = __DIR__ . "/template.xml";
32
  /** @var RssExtensionsCollection|IRssExtension[] */
33
  public RssExtensionsCollection $extensions;
34
  /** @var callable[] */
35
  public array $onBeforeGenerate = [];
36
  /** @var callable[] */
37
  public array $onAddItem = [];
38
  /** @var callable[] */
39
  public array $onAfterGenerate = [];
40
41
  public function __construct() {
42 1
    $this->extensions = RssExtensionsCollection::fromArray([new RssCore()]);
43 1
  }
44
45
  protected function getDataSource(): ?callable {
46
    return $this->dataSource;
47
  }
48
49
  protected function setDataSource(callable $dataSource): void {
50 1
    $this->dataSource = $dataSource;
51 1
  }
52
53
  protected function getTemplate(): string {
54 1
    return $this->template;
55
  }
56
57
  /**
58
   * @throws \RuntimeException
59
   */
60
  protected function setTemplate(string $template): void {
61 1
    if(!is_file($template) || !is_readable($template)) {
62 1
      throw new \RuntimeException("File $template does not exist or is not readable.");
63
    }
64 1
    $this->template = $template;
65 1
  }
66
  
67
  /**
68
   * @throws InvalidStateException
69
   * @throws \InvalidArgumentException
70
   */
71
  private function getData(): Collection {
72 1
    if($this->dataSource === null) {
73 1
      throw new InvalidStateException("Data source for RSS generator is not set.");
74
    }
75 1
    $items = call_user_func($this->dataSource);
76 1
    if(!$items instanceof Collection) {
77 1
      throw new \InvalidArgumentException("Callback for data source for RSS generator has to return an instance of  " . Collection::class . ".");
0 ignored issues
show
introduced by
Line exceeds 120 characters; contains 145 characters
Loading history...
78
    }
79 1
    return $items;
80
  }
81
82
  private function writeProperty(\SimpleXMLElement &$channel, array $info, string $property): void {
83 1
    $value = Arrays::get($info, $property, "");
84 1
    if(!$value instanceof IXmlConvertible) {
85 1
      $value = new GenericElement($property, $value);
86
    }
87 1
    $value->appendToXml($channel->channel);
88 1
  }
89
90
  /**
91
   * @throws InvalidStateException
92
   * @throws \InvalidArgumentException
93
   */
94
  public function generate(array $info): string {
95 1
    $this->onBeforeGenerate($this, $info);
96 1
    $items = $this->getData();
97 1
    $resolver = new OptionsResolver();
98 1
    foreach($this->extensions as $extension) {
99 1
      $extension->configureChannelOptions($resolver, $this);
100
    }
101 1
    $info = $resolver->resolve($info);
102
    /** @var \SimpleXMLElement $channel */
103 1
    $channel = simplexml_load_file($this->template);
104 1
    foreach($this->extensions as $extension) {
105 1
      if($extension->getName() !== "" && $extension->getNamespace() !== "") {
106 1
        $channel->addAttribute(static::NAMESPACE_ATTRIBUTE_HACK . $extension->getName(), $extension->getNamespace());
107
      }
108
    }
109 1
    $properties = $resolver->getDefinedOptions();
110 1
    foreach($properties as $property) {
111 1
      $this->writeProperty($channel, $info, $property);
112
    }
113 1
    if($this->generator !== "") {
114 1
      $channel->channel->generator = $this->generator;
115
    }
116 1
    if($this->docs !== "") {
117 1
      $channel->channel->docs = $this->docs;
118
    }
119
    /** @var RssChannelItem $item */
120 1
    foreach($items as $item) {
121
      /** @var \SimpleXMLElement $i */
122 1
      $i = $channel->channel->addChild("item");
123 1
      $item->toXml($i, $this);
124 1
      $this->onAddItem($this, $channel, $item, $i);
125
    }
126 1
    $this->onAfterGenerate($this, $info);
127 1
    $dom = new \DOMDocument();
128 1
    $dom->preserveWhiteSpace = false;
129 1
    $dom->formatOutput = true;
130 1
    $xml = $channel->asXML();
131 1
    $xml = str_replace(static::NAMESPACE_ATTRIBUTE_HACK, "xmlns:", $xml);
132 1
    $dom->loadXML($xml);
133 1
    return (string) $dom->saveXML();
134
  }
135
  
136
  /**
137
   * @throws InvalidStateException
138
   * @throws \InvalidArgumentException
139
   */
140
  public function response(array $info): RssResponse {
141 1
    return new RssResponse($this->generate($info));
142
  }
143
}
144
?>