Completed
Push — master ( 4096d3...cbeb3c )
by Josh
23:32
created

Repository::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 2
crap 3
1
<?php
2
3
/**
4
* @package   s9e\TextFormatter
5
* @copyright Copyright (c) 2010-2018 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\TextFormatter\Plugins\BBCodes\Configurator;
9
10
use DOMDocument;
11
use DOMElement;
12
use DOMXPath;
13
use InvalidArgumentException;
14
use RuntimeException;
15
16
class Repository
17
{
18
	/**
19
	* @var BBCodeMonkey Instance of BBCodeMonkey used to parse definitions
20
	*/
21
	protected $bbcodeMonkey;
22
23
	/**
24
	* @var DOMDocument Repository document
25
	*/
26
	protected $dom;
27
28
	/**
29
	* Constructor
30
	*
31
	* @param  mixed        $value        Either a DOMDocument or the path to a repository's XML file
32
	* @param  BBCodeMonkey $bbcodeMonkey Instance of BBCodeMonkey used to parse definitions
33
	*/
34 15
	public function __construct($value, BBCodeMonkey $bbcodeMonkey)
35
	{
36 15
		if (!($value instanceof DOMDocument))
37
		{
38 5
			$dom = new DOMDocument;
39 5
			$dom->preserveWhiteSpace = false;
40 5
			if (!@$dom->load($value))
41
			{
42 2
				throw new InvalidArgumentException(var_export($value, true) . ' is not a valid BBCode repository file');
43
			}
44 3
			$value = $dom;
45
		}
46
47 13
		$this->bbcodeMonkey = $bbcodeMonkey;
48 13
		$this->dom          = $value;
49 13
	}
50
51
	/**
52
	* Get a BBCode and its associated tag from this repository
53
	*
54
	* @param  string $name Name of the entry in the repository
55
	* @param  array  $vars Replacement variables
56
	* @return array        Array with three elements: "bbcode", "name" and "tag"
57
	*/
58 11
	public function get($name, array $vars = [])
59
	{
60
		// Everything before # should be a BBCode name
61 11
		$name = preg_replace_callback(
62 11
			'/^[^#]+/',
63 11
			function ($m)
64
			{
65 11
				return BBCode::normalizeName($m[0]);
66 11
			},
67
			$name
68
		);
69
70
		$xpath = new DOMXPath($this->dom);
71
		$node  = $xpath->query('//bbcode[@name="' . htmlspecialchars($name) . '"]')->item(0);
72
73
		if (!($node instanceof DOMElement))
74
		{
75
			throw new RuntimeException("Could not find '" . $name . "' in repository");
76
		}
77
78
		// Clone the node so we don't end up modifying the node in the repository
79
		$clonedNode = $node->cloneNode(true);
80
81
		// Replace all the <var> descendants if applicable
82
		foreach ($xpath->query('.//var', $clonedNode) as $varNode)
83
		{
84
			$varName = $varNode->getAttribute('name');
85
86
			if (isset($vars[$varName]))
87
			{
88
				$varNode->parentNode->replaceChild(
89
					$this->dom->createTextNode($vars[$varName]),
90
					$varNode
91
				);
92
			}
93
		}
94
95
		// Now we can parse the BBCode usage and prepare the template.
96
		// Grab the content of the <usage> element then use BBCodeMonkey to parse it
97
		$usage      = $xpath->evaluate('string(usage)', $clonedNode);
98
		$template   = $xpath->evaluate('string(template)', $clonedNode);
99
		$config     = $this->bbcodeMonkey->create($usage, $template);
100
		$bbcode     = $config['bbcode'];
101
		$bbcodeName = $config['bbcodeName'];
102
		$tag        = $config['tag'];
103
104
		// Set the optional tag name
105
		if ($node->hasAttribute('tagName'))
106
		{
107
			$bbcode->tagName = $node->getAttribute('tagName');
108
		}
109
110
		// Set the rules
111
		foreach ($xpath->query('rules/*', $node) as $ruleNode)
112
		{
113
			$methodName = $ruleNode->nodeName;
114
			$args       = [];
115
116
			if ($ruleNode->textContent)
117
			{
118
				$args[] = $ruleNode->textContent;
119
			}
120
121
			call_user_func_array([$tag->rules, $methodName], $args);
122
		}
123
124
		return [
125
			'bbcode'     => $bbcode,
126
			'bbcodeName' => $bbcodeName,
127
			'tag'        => $tag
128
		];
129
	}
130
}