Completed
Push — master ( 092da6...b7a681 )
by Jakub
02:00
created

Generator.php$0 ➔ setDateTimeFormat()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
c 0
b 0
f 0
dl 0
loc 2
ccs 1
cts 1
cp 1
crap 1
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-write callable $dataSource
15
 * @property int $shortenDescription
16
 * @property string $dateTimeFormat
17
 * @property string $generator
18
 * @property string $docs
19
 * @property string $template
20
 * @method void onBeforeGenerate(Generator $generator, array $info)
21
 * @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...
22
 * @method void onAfterGenerate(Generator $generator, array $info)
23
 */
24 1
final class Generator {
25 1
  use \Nette\SmartObject;
26
27
  /** @var string */
28
  protected $dateTimeFormat = "r";
29
  /** @var callable|null */
30
  protected $dataSource = null;
31
  /** @var int */
32
  protected $shortenDescription = 150;
33
  /** @var string */
34
  protected $generator = "Nexendrie RSS";
35
  /** @var string */
36
  protected $docs = "http://www.rssboard.org/rss-specification";
37
  /** @var string */
38
  protected $template = __DIR__ . "/template.xml";
39
  /** @var \Nexendrie\Utils\Collection|IRssExtension[] */
40
  protected $extensions;
41
  /** @var callable[] */
42
  public $onBeforeGenerate = [];
43
  /** @var callable[] */
44
  public $onAddItem = [];
45
  /** @var callable[] */
46
  public $onAfterGenerate = [];
47
48
  public function __construct() {
49 1
    $this->extensions = new class extends \Nexendrie\Utils\Collection {
50
      /** @var string */
51
      protected $class = IRssExtension::class;
52
    };
53 1
    $this->extensions[] = new RssCore();
54 1
  }
55
56
  protected function setDataSource(callable $dataSource): void {
57 1
    $this->dataSource = $dataSource;
58 1
  }
59
60
  protected function getShortenDescription(): int {
61 1
    return $this->shortenDescription;
62
  }
63
64
  protected function setShortenDescription(int $value): void {
65 1
    $this->shortenDescription = $value;
66 1
  }
67
68
  protected function getDateTimeFormat(): string {
69 1
    return $this->dateTimeFormat;
70
  }
71
72
  protected function setDateTimeFormat(string $format): void {
73 1
    $this->dateTimeFormat = $format;
74 1
  }
75
76
  protected function getGenerator(): string {
77 1
    return $this->generator;
78
  }
79
80
  protected function setGenerator(string $generator): void {
81 1
    $this->generator = $generator;
82 1
  }
83
84
  protected function getDocs(): string {
85 1
    return $this->docs;
86
  }
87
88
  protected function setDocs(string $docs): void {
89 1
    $this->docs = $docs;
90 1
  }
91
92
  protected function getTemplate(): string {
93 1
    return $this->template;
94
  }
95
  
96
  /**
97
   * @throws \RuntimeException
98
   */
99
  protected function setTemplate(string $template): void {
100 1
    if(!is_file($template) || !is_readable($template)) {
101 1
      throw new \RuntimeException("File $template does not exist or is not readable.");
102
    }
103 1
    $this->template = $template;
104 1
  }
105
106
  /**
107
   * @internal
108
   */
109
  public function getExtensions(): \Nexendrie\Utils\Collection {
110 1
    return $this->extensions;
111
  }
112
  
113
  /**
114
   * @throws InvalidStateException
115
   * @throws \InvalidArgumentException
116
   */
117
  protected function getData(): Collection {
118 1
    if($this->dataSource === null) {
119 1
      throw new InvalidStateException("Data source for RSS generator is not set.");
120
    }
121 1
    $items = call_user_func($this->dataSource);
122 1
    if(!$items instanceof Collection) {
123 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...
124
    }
125 1
    return $items;
126
  }
127
  
128
  protected function writeProperty(\SimpleXMLElement &$channel, array $info, string $property): void {
129 1
    $value = Arrays::get($info, $property, "");
130 1
    if(!$value instanceof IXmlConvertible) {
131 1
      $value = new GenericElement($property, $value);
132
    }
133 1
    $value->appendToXml($channel->channel);
134 1
  }
135
136
  protected function configureOptions(OptionsResolver $resolver): void {
137 1
    foreach($this->extensions as $extension) {
138 1
      $extension->configureChannelOptions($resolver, $this);
139
    }
140 1
  }
141
  
142
  /**
143
   * @throws InvalidStateException
144
   * @throws \InvalidArgumentException
145
   */
146
  public function generate(array $info): string {
147 1
    $this->onBeforeGenerate($this, $info);
148 1
    $items = $this->getData();
149 1
    $resolver = new OptionsResolver();
150 1
    $this->configureOptions($resolver);
151 1
    $info = $resolver->resolve($info);
152
    /** @var \SimpleXMLElement $channel */
153 1
    $channel = simplexml_load_file($this->template);
154 1
    $properties = $resolver->getDefinedOptions();
155 1
    foreach($properties as $property) {
156 1
      $this->writeProperty($channel, $info, $property);
157
    }
158 1
    if($this->generator !== "") {
159 1
      $channel->channel->generator = $this->generator;
160
    }
161 1
    if($this->docs !== "") {
162 1
      $channel->channel->docs = $this->docs;
163
    }
164
    /** @var RssChannelItem $item */
165 1
    foreach($items as $item) {
166
      /** @var \SimpleXMLElement $i */
167 1
      $i = $channel->channel->addChild("item");
168 1
      $item->toXml($i, $this);
169 1
      $this->onAddItem($this, $channel, $item, $i);
170
    }
171 1
    $this->onAfterGenerate($this, $info);
172 1
    $dom = new \DOMDocument();
173 1
    $dom->preserveWhiteSpace = false;
174 1
    $dom->formatOutput = true;
175 1
    $dom->loadXML($channel->asXML());
176 1
    return $dom->saveXML();
177
  }
178
  
179
  /**
180
   * @throws InvalidStateException
181
   * @throws \InvalidArgumentException
182
   */
183
  public function response(array $info): RssResponse {
184 1
    return new RssResponse($this->generate($info));
185
  }
186
}
187
?>