Completed
Push — main ( d12b31...3b4b71 )
by Andreas
24s queued 12s
created

HolidayIteratorFactory::getElement()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 10
rs 10
cc 3
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Copyright (c) Andreas Heigl<[email protected]>
7
 *
8
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9
 * of this software and associated documentation files (the "Software"), to deal
10
 * in the Software without restriction, including without limitation the rights
11
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
 * copies of the Software, and to permit persons to whom the Software is
13
 * furnished to do so, subject to the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
 * THE SOFTWARE.
25
 *
26
 * @author    Andreas Heigl<[email protected]>
27
 * @copyright Andreas Heigl
28
 * @license   http://www.opensource.org/licenses/mit-license.php MIT-License
29
 * @since     09.03.2017
30
 * @link      http://github.com/heiglandreas/org.heigl.Holidaychecker
31
 */
32
33
namespace Org_Heigl\Holidaychecker;
34
35
use DOMDocument;
36
use DOMElement;
37
use Exception;
38
use Org_Heigl\Holidaychecker\Factory\DateFactory;
39
use Org_Heigl\Holidaychecker\Factory\DateFollowupFactory;
40
use Org_Heigl\Holidaychecker\Factory\DecorateFromDomElement;
41
use Org_Heigl\Holidaychecker\Factory\EasterFactory;
42
use Org_Heigl\Holidaychecker\Factory\EasterOrthodoxFactory;
43
use Org_Heigl\Holidaychecker\Factory\ItemFromDomElementCreator;
44
use Org_Heigl\Holidaychecker\Factory\ObservanceDecoratorFactory;
45
use Org_Heigl\Holidaychecker\Factory\RelativeFactory;
46
use RuntimeException;
47
use Throwable;
48
use UnexpectedValueException;
49
use function is_readable;
50
use function sprintf;
51
52
class HolidayIteratorFactory
53
{
54
	/** @var ItemFromDomElementCreator[] */
55
	private $factories;
56
57
	/** @var DecorateFromDomElement[] */
58
	private $decorators;
59
60
	public function __construct()
61
	{
62
		$this->factories = [
63
			new EasterFactory(),
64
			new EasterOrthodoxFactory(),
65
			new DateFactory(),
66
			new DateFollowupFactory(),
67
			new RelativeFactory(),
68
		];
69
70
		$this->decorators = [
71
			new ObservanceDecoratorFactory(),
72
		];
73
	}
74
75
	/**
76
	 * Create a HolidayIterator from an XML-File
77
	 *
78
	 * The provided XML-File has to validate against the holiday.xsd-file you
79
	 * can find in this projects "share" folder.
80
	 *
81
	 * @param string $file
82
	 *
83
	 * @return HolidayIterator
84
	 */
85
	public function createIteratorFromXmlFile(string $file): HolidayIterator
86
	{
87
		$iterator = new HolidayIterator();
88
89
		$dom = new DOMDocument('1.0', 'UTF-8');
90
		$dom->load($file);
91
		$dom->xinclude();
92
93
		if (!@$dom->schemaValidate(__DIR__ . '/../share/holidays.xsd')) {
94
			throw new Exception('XML-File does not validate agains schema');
95
		}
96
		foreach ($dom->documentElement->childNodes as $child) {
97
			if (!$child instanceof DOMElement) {
98
				continue;
99
			}
100
			if ($child->nodeName === 'resources') {
101
				continue;
102
			}
103
104
			try {
105
				$element = $this->getElement($child);
106
				$element = $this->decorateElement($element, $child);
107
				$iterator->append($element);
108
			} catch (Throwable $e) {
109
				// Do nothing on purpose
110
			}
111
		}
112
113
		return $iterator;
114
	}
115
116
	/**
117
	 * Create a HolidayIterator from an ISO 3166-code.
118
	 *
119
	 * @param string $isoCode
120
	 *
121
	 * @return HolidayIterator
122
	 */
123
	public function createIteratorFromISO3166(string $isoCode): HolidayIterator
124
	{
125
		$file = __DIR__ . '/../share/%s.xml';
126
		$file1 = sprintf($file, $isoCode);
127
128
		if (!is_readable($file1)) {
129
			throw new UnexpectedValueException(sprintf(
130
				'There is no holiday-file for %s',
131
				$isoCode
132
			));
133
		}
134
135
		return $this->createIteratorFromXmlFile($file1);
136
	}
137
138
	private function getElement(DOMElement $child): HolidayIteratorItemInterface
139
	{
140
		foreach ($this->factories as $factory) {
141
			$element = $factory->itemFromDomElement($child);
142
			if ($element instanceof HolidayIteratorItemInterface) {
143
				return $element;
144
			}
145
		}
146
147
		throw new RuntimeException('Unknown element encountered');
148
	}
149
150
	private function decorateElement(HolidayIteratorItemInterface $element, DOMElement $child): HolidayIteratorItemInterface
151
	{
152
		foreach ($this->decorators as $decorator) {
153
			$element = $decorator->decorate($element, $child);
154
		}
155
156
		return $element;
157
	}
158
}
159