Seditio Source
Root |
./othercms/phpBB3/vendor/s9e/text-formatter/src/Plugins/BBCodes/Configurator/Repository.php
<?php

/**
* @package   s9e\TextFormatter
* @copyright Copyright (c) 2010-2021 The s9e authors
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
*/
namespace s9e\TextFormatter\Plugins\BBCodes\Configurator;

use
DOMDocument;
use
DOMElement;
use
DOMXPath;
use
InvalidArgumentException;
use
RuntimeException;
use
s9e\TextFormatter\Configurator\Items\Tag;

class
Repository
{
   
/**
    * @var BBCodeMonkey Instance of BBCodeMonkey used to parse definitions
    */
   
protected $bbcodeMonkey;

   
/**
    * @var DOMDocument Repository document
    */
   
protected $dom;

   
/**
    * @var DOMXPath
    */
   
protected $xpath;

   
/**
    * Constructor
    *
    * @param  mixed        $value        Either a DOMDocument or the path to a repository's XML file
    * @param  BBCodeMonkey $bbcodeMonkey Instance of BBCodeMonkey used to parse definitions
    */
   
public function __construct($value, BBCodeMonkey $bbcodeMonkey)
    {
       
$this->bbcodeMonkey = $bbcodeMonkey;
       
$this->dom          = ($value instanceof DOMDocument) ? $value : $this->loadRepository($value);
       
$this->xpath        = new DOMXPath($this->dom);
    }

   
/**
    * Get a BBCode and its associated tag from this repository
    *
    * @param  string $name Name of the entry in the repository
    * @param  array  $vars Replacement variables
    * @return array        Array with three elements: "bbcode", "name" and "tag"
    */
   
public function get($name, array $vars = [])
    {
       
$name = BBCode::normalizeName($name);
       
$node = $this->xpath->query('//bbcode[@name="' . $name . '"]')->item(0);
        if (!(
$node instanceof DOMElement))
        {
            throw new
RuntimeException("Could not find '" . $name . "' in repository");
        }

       
// Clone the node so we don't end up modifying the node in the repository
       
$node = $node->cloneNode(true);

       
// Replace all the <var> descendants if applicable
       
$this->replaceVars($node, $vars);

       
// Now we can parse the BBCode usage and prepare the template.
        // Grab the content of the <usage> element then use BBCodeMonkey to parse it
       
$usage    = $this->xpath->evaluate('string(usage)', $node);
       
$template = $this->xpath->evaluate('string(template)', $node);
       
$config   = $this->bbcodeMonkey->create($usage, $template);

       
// Set the optional tag name
       
if ($node->hasAttribute('tagName'))
        {
           
$config['bbcode']->tagName = $node->getAttribute('tagName');
        }

       
// Set the rules
       
$this->addRules($node, $config['tag']);

        return
$config;
    }

   
/**
    * Add rules to given tag based on given definition
    *
    * @param  DOMElement $node
    * @param  Tag        $tag
    * @return void
    */
   
protected function addRules(DOMElement $node, Tag $tag)
    {
        foreach (
$this->xpath->query('rules/*', $node) as $ruleNode)
        {
           
$methodName = $ruleNode->nodeName;
           
$args       = [];
            if (
$ruleNode->textContent)
            {
               
$args[] = $ruleNode->textContent;
            }

           
call_user_func_array([$tag->rules, $methodName], $args);
        }
    }

   
/**
    * Create an exception for a bad repository file path
    *
    * @param  string $filepath
    * @return InvalidArgumentException
    */
   
protected function createRepositoryException($filepath)
    {
        return new
InvalidArgumentException(var_export($filepath, true) . ' is not a valid BBCode repository file');
    }

   
/**
    * Load a repository file into a DOMDocument
    *
    * @param  string $filepath
    * @return DOMDocument
    */
   
protected function loadRepository($filepath)
    {
        if (!
file_exists($filepath))
        {
            throw
$this->createRepositoryException($filepath);
        }

       
$dom = new DOMDocument;
       
$dom->preserveWhiteSpace = false;
        if (!
$dom->loadXML(file_get_contents($filepath), LIBXML_NOERROR))
        {
            throw
$this->createRepositoryException($filepath);
        }

        return
$dom;
    }

   
/**
    * Replace var elements in given definition
    *
    * @param  DOMElement $node
    * @param  array      $vars
    * @return void
    */
   
protected function replaceVars(DOMElement $node, array $vars)
    {
        foreach (
$this->xpath->query('.//var', $node) as $varNode)
        {
           
$varName = $varNode->getAttribute('name');

            if (isset(
$vars[$varName]))
            {
               
$varNode->parentNode->replaceChild(
                   
$this->dom->createTextNode($vars[$varName]),
                   
$varNode
               
);
            }
        }
    }
}