Created
February 13, 2017 05:44
-
-
Save joshuaadickerson/c3669645a6ae59e37a6d46b4efe1bed1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Elkarte\Messages\Formatters; | |
class ForumML | |
{ | |
const KNOWN_NODE_TYPES = [ | |
'TEXT' => 1, | |
'NEW_LINE' => 2, | |
'EMPTY_LINE' => 3, | |
'TAG' => 4, | |
'EMOJI' => 5, | |
'LINK' => 6, | |
]; | |
public function format($message) | |
{ | |
foreach ($message as $node) { | |
if (!$this->isKnownType($node->getType())) { | |
throw new InvalidNodeTypeException; | |
} | |
$this->formatChildren($node); | |
} | |
} | |
public function isKnownType($type) | |
{ | |
$knownTypes = self::KNOWN_NODE_TYPES; | |
return isset($knownTypes[$type]); | |
} | |
protected function formatChildren($node) | |
{ | |
if ($node->hasChildren()) { | |
foreach ($node->getChildren() as $childNode) { | |
$this->format($childNode); | |
} | |
} | |
} | |
} | |
class NodeFactory | |
{ | |
protected $factories = []; | |
public function newNode($node, AbstractNode $parent = null) | |
{ | |
if (!isset($node['type']) || !$this->nodeFactory->isKnownType($node['type'])) { | |
throw new InvalidNodeTypeException; | |
} | |
$newNode = null; | |
if (isset($this->factories[$node['type']])) { | |
$newNode = $this->factories[$node['type']]($node, $this, $parent); | |
} else { | |
$newNode = $this->getNodeFromType($node, $parent); | |
} | |
return $newNode; | |
} | |
public function setFactoryForType(callable $callback, $type) | |
{ | |
$this->factories[$type] = $callback; | |
return $this; | |
} | |
// @todo bad name | |
protected function getNodeFromType($node, AbstractNode $parent = null) | |
{ | |
$newNode = null; | |
switch ($node['type']) { | |
case NodeFactory::TAG: | |
$newNode = new TagNode($node, $this, $parent); | |
break; | |
case NodeFactory::TEXT: | |
$newNode = new TextNode($node, $this, $parent); | |
break; | |
} | |
return $newNode; | |
} | |
} | |
abstract class AbstractNode | |
{ | |
protected $type; | |
protected $factory; | |
protected $parent; | |
protected $value; | |
protected $children = []; | |
protected $attributes = []; | |
abstract public function render(); | |
abstract public function getType(); | |
abstract public function validate(); | |
/** | |
* AbstractNode constructor. | |
* @param array $node the unserialized array | |
* @param NodeFactory $nodeFactory | |
* @param AbstractNode|null $parent | |
*/ | |
public function __construct(array $node, NodeFactory $nodeFactory, AbstractNode $parent = null) | |
{ | |
$this->nodeFactory = $nodeFactory; | |
$this->type = $this->getType(); | |
if (isset($node['attributes'])) { | |
$this->attributes = $node['attributes']; | |
} | |
if (isset($node['children'])) { | |
$this->setChildren($node['children']); | |
} | |
if (isset($node['value'])) { | |
$this->value = $node['value']; | |
} | |
$this->validate(); | |
} | |
public function __toString() | |
{ | |
$this->render(); | |
} | |
public function __sleep() | |
{ | |
return array_filter([ | |
'type' => $this->type, | |
'value' => $this->value, | |
'attributes' => $this->attributes, | |
'children' => array_reduce($this->children, function ($children, $child) { | |
$children[] = $child->__sleep; | |
return $children; | |
}, []), | |
]); | |
} | |
public function hasAttributes() | |
{ | |
return !empty($this->attributes); | |
} | |
public function getAttributes() | |
{ | |
return $this->attributes; | |
} | |
public function hasValue() | |
{ | |
return isset($this->value); | |
} | |
public function getValue() | |
{ | |
return $this->value; | |
} | |
public function hasParent() | |
{ | |
return $this->parent instanceof AbstractNode; | |
} | |
public function getParent() | |
{ | |
return $this->parent; | |
} | |
public function hasParentOfType($type) | |
{ | |
return $this->hasParent() && ( | |
$this->getParent()->getType() === $type | |
|| $this->getParent()->hasParentOfType($type)); | |
} | |
protected function setParent(AbstractNode $parent) | |
{ | |
$this->parent = $parent; | |
return $this; | |
} | |
public function hasChildren() | |
{ | |
return !empty($this->children); | |
} | |
public function getChildren() | |
{ | |
return $this->children; | |
} | |
protected function setChildren(array $nodes) | |
{ | |
$this->children = []; | |
foreach ($nodes as $node) { | |
$this->children[] = $this->factory->newNode($node, $this); | |
} | |
return $this; | |
} | |
} | |
// namespace Nodes; | |
class TagNode extends AbstractNode | |
{ | |
const TYPE = 'TAG'; | |
public function getType() | |
{ | |
return self::TYPE; | |
} | |
public function validate() | |
{ | |
if (!isset($this->value)) { | |
throw new \Exception('Invalid value for Tag node'); | |
} | |
$this->tag = $this->factory->getTagFactory()->newTag($this); | |
return true; | |
} | |
public function render() | |
{ | |
return $this->tag->render($this); | |
} | |
} | |
class TextNode extends AbstractNode | |
{ | |
const TYPE = 'TEXT'; | |
public function getType() | |
{ | |
return self::TYPE; | |
} | |
public function validate() | |
{ | |
return true; | |
} | |
public function render() | |
{ | |
return $this->renderEmoji(); | |
} | |
public function renderEmoji() | |
{ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment