Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshuaadickerson/c3669645a6ae59e37a6d46b4efe1bed1 to your computer and use it in GitHub Desktop.
Save joshuaadickerson/c3669645a6ae59e37a6d46b4efe1bed1 to your computer and use it in GitHub Desktop.
<?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