Completed
Push — master ( 1052a1...74f7bf )
by Josh
14:35
created

Repository::addRules()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
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
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'))
1 ignored issue
show
Bug introduced by
The method hasAttribute() does not exist on DOMNode. Did you maybe mean hasAttributes()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
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  mixed $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
}