Completed
Push — master ( aa5f96...588c7e )
by Josh
13:47
created

Repository   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 3
dl 0
loc 148
ccs 45
cts 45
cp 1
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 2
B get() 0 32 3
A addRules() 0 14 3
A createRepositoryException() 0 4 1
A loadRepository() 0 16 3
A replaceVars() 0 15 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
use s9e\TextFormatter\Configurator\Items\Tag;
16
17
class Repository
18
{
19
	/**
20
	* @var BBCodeMonkey Instance of BBCodeMonkey used to parse definitions
21
	*/
22
	protected $bbcodeMonkey;
23
24
	/**
25
	* @var DOMDocument Repository document
26
	*/
27
	protected $dom;
28
29
	/**
30
	* @var DOMXPath
31
	*/
32
	protected $xpath;
33
34
	/**
35
	* Constructor
36
	*
37
	* @param  mixed        $value        Either a DOMDocument or the path to a repository's XML file
38
	* @param  BBCodeMonkey $bbcodeMonkey Instance of BBCodeMonkey used to parse definitions
39
	*/
40 14
	public function __construct($value, BBCodeMonkey $bbcodeMonkey)
41
	{
42 14
		$this->bbcodeMonkey = $bbcodeMonkey;
43 14
		$this->dom          = ($value instanceof DOMDocument) ? $value : $this->loadRepository($value);
44 12
		$this->xpath        = new DOMXPath($this->dom);
45 12
	}
46
47
	/**
48
	* Get a BBCode and its associated tag from this repository
49
	*
50
	* @param  string $name Name of the entry in the repository
51
	* @param  array  $vars Replacement variables
52
	* @return array        Array with three elements: "bbcode", "name" and "tag"
53
	*/
54 10
	public function get($name, array $vars = [])
55
	{
56 10
		$name = BBCode::normalizeName($name);
57 10
		$node = $this->xpath->query('//bbcode[@name="' . $name . '"]')->item(0);
58 10
		if (!($node instanceof DOMElement))
59
		{
60 1
			throw new RuntimeException("Could not find '" . $name . "' in repository");
61
		}
62
63
		// Clone the node so we don't end up modifying the node in the repository
64 9
		$node = $node->cloneNode(true);
65
66
		// Replace all the <var> descendants if applicable
67 9
		$this->replaceVars($node, $vars);
68
69
		// Now we can parse the BBCode usage and prepare the template.
70
		// Grab the content of the <usage> element then use BBCodeMonkey to parse it
71 9
		$usage    = $this->xpath->evaluate('string(usage)', $node);
72 9
		$template = $this->xpath->evaluate('string(template)', $node);
73 9
		$config   = $this->bbcodeMonkey->create($usage, $template);
74
75
		// Set the optional tag name
76 9
		if ($node->hasAttribute('tagName'))
77
		{
78 1
			$config['bbcode']->tagName = $node->getAttribute('tagName');
79
		}
80
81
		// Set the rules
82 9
		$this->addRules($node, $config['tag']);
83
84 9
		return $config;
85
	}
86
87
	/**
88
	* Add rules to given tag based on given definition
89
	*
90
	* @param  DOMElement $node
91
	* @param  Tag        $tag
92
	* @return void
93
	*/
94 9
	protected function addRules(DOMElement $node, Tag $tag)
95
	{
96 9
		foreach ($this->xpath->query('rules/*', $node) as $ruleNode)
97
		{
98 2
			$methodName = $ruleNode->nodeName;
99 2
			$args       = [];
100 2
			if ($ruleNode->textContent)
101
			{
102 1
				$args[] = $ruleNode->textContent;
103
			}
104
105 2
			call_user_func_array([$tag->rules, $methodName], $args);
106
		}
107 9
	}
108
109
	/**
110
	* Create an exception for a bad repository file path
111
	*
112
	* @param  string $filepath
113
	* @return InvalidArgumentException
114
	*/
115 2
	protected function createRepositoryException($filepath)
116
	{
117 2
		return new InvalidArgumentException(var_export($filepath, true) . ' is not a valid BBCode repository file');
118
	}
119
120
	/**
121
	* Load a repository file into a DOMDocument
122
	*
123
	* @param  string $filepath
124
	* @return DOMDocument
125
	*/
126 5
	protected function loadRepository($filepath)
127
	{
128 5
		if (!file_exists($filepath))
129
		{
130 1
			throw $this->createRepositoryException($filepath);
131
		}
132
133 4
		$dom = new DOMDocument;
134 4
		$dom->preserveWhiteSpace = false;
135 4
		if (!$dom->loadXML(file_get_contents($filepath), LIBXML_NOERROR))
136
		{
137 1
			throw $this->createRepositoryException($filepath);
138
		}
139
140 3
		return $dom;
141
	}
142
143
	/**
144
	* Replace var elements in given definition
145
	*
146
	* @param  DOMElement $node
147
	* @return array      $vars
148
	*/
149 9
	protected function replaceVars(DOMElement $node, array $vars)
150
	{
151 9
		foreach ($this->xpath->query('.//var', $node) as $varNode)
152
		{
153 5
			$varName = $varNode->getAttribute('name');
154
155 5
			if (isset($vars[$varName]))
156
			{
157 4
				$varNode->parentNode->replaceChild(
158 4
					$this->dom->createTextNode($vars[$varName]),
159 5
					$varNode
160
				);
161
			}
162
		}
163
	}
164
}