Passed
Push — main ( ce132f...25dcff )
by Andreas
01:51
created

createIteratorFromXmlFile()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 20
c 2
b 0
f 0
dl 0
loc 34
rs 8.6666
cc 7
nc 9
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 Org_Heigl\Holidaychecker\Factory\SwapDecoratorFactory;
47
use RuntimeException;
48
use Throwable;
49
use UnexpectedValueException;
50
use function is_readable;
51
use function sprintf;
52
53
class HolidayIteratorFactory
54
{
55
	/** @var ItemFromDomElementCreator[] */
56
	private $factories;
57
58
	/** @var DecorateFromDomElement[] */
59
	private $decorators;
60
61
	public function __construct()
62
	{
63
		$this->factories = [
64
			new EasterFactory(),
65
			new EasterOrthodoxFactory(),
66
			new DateFactory(),
67
			new DateFollowupFactory(),
68
			new RelativeFactory(),
69
		];
70
71
		$this->decorators = [
72
			new ObservanceDecoratorFactory(),
73
			new SwapDecoratorFactory(),
74
		];
75
	}
76
77
	/**
78
	 * Create a HolidayIterator from an ISO 3166-code.
79
	 *
80
	 * @param string $isoCode
81
	 *
82
	 * @return HolidayIterator
83
	 */
84
	public function createIteratorFromISO3166(string $isoCode): HolidayIterator
85
	{
86
		$file = __DIR__ . '/../share/%s.xml';
87
		$file1 = sprintf($file, $isoCode);
88
89
		if (!is_readable($file1)) {
90
			throw new UnexpectedValueException(sprintf(
91
				'There is no holiday-file for %s',
92
				$isoCode
93
			));
94
		}
95
96
		return $this->createIteratorFromXmlFile($file1);
97
	}
98
99
	/**
100
	 * Create a HolidayIterator from an XML-File
101
	 *
102
	 * The provided XML-File has to validate against the holiday.xsd-file you
103
	 * can find in this projects "share" folder.
104
	 *
105
	 * @param string $file
106
	 *
107
	 * @return HolidayIterator
108
	 */
109
	public function createIteratorFromXmlFile(string $file): HolidayIterator
110
	{
111
		$iterator = new HolidayIterator();
112
113
		$dom = new DOMDocument('1.0', 'UTF-8');
114
		$dom->load($file);
115
		$dom->xinclude();
116
117
		if (!@$dom->schemaValidate(__DIR__ . '/../share/holidays.xsd')) {
118
			throw new Exception('XML-File does not validate agains schema');
119
		}
120
121
		$element = $dom->documentElement;
122
		if ($element === null) {
123
			return $iterator;
124
		}
125
		foreach ($element->childNodes as $child) {
126
			if (!$child instanceof DOMElement) {
127
				continue;
128
			}
129
			if ($child->nodeName === 'resources') {
130
				continue;
131
			}
132
133
			try {
134
				$element = $this->getElement($child);
135
				$element = $this->decorateElement($element, $child);
136
				$iterator->append($element);
137
			} catch (Throwable $e) {
138
				// Do nothing on purpose
139
			}
140
		}
141
142
		return $iterator;
143
	}
144
145
	private function getElement(DOMElement $child): HolidayIteratorItemInterface
146
	{
147
		foreach ($this->factories as $factory) {
148
			$element = $factory->itemFromDomElement($child);
149
			if ($element instanceof HolidayIteratorItemInterface) {
150
				return $element;
151
			}
152
		}
153
154
		throw new RuntimeException('Unknown element encountered');
155
	}
156
157
	private function decorateElement(HolidayIteratorItemInterface $element, DOMElement $child): HolidayIteratorItemInterface
158
	{
159
		foreach ($this->decorators as $decorator) {
160
			$element = $decorator->decorate($element, $child);
161
		}
162
163
		return $element;
164
	}
165
}
166