A fork of potaka/bbcode to handle future maintenance
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.5KB

  1. <?php
  2. namespace Knockout\BbCode;
  3. use Knockout\BbCode\Tag\TagInterface;
  4. use Knockout\BbCode\Tokenizer\Tag as TokenTag;
  5. use Knockout\BbCode\TagBag\TagBag;
  6. use Knockout\BbCode\Tag\TextTag;
  7. use Knockout\BbCode\Tag\UnknownSimpleType;
  8. /**
  9. * Format tokens to html
  10. *
  11. * @author po_taka <angel.koilov@gmail.com>
  12. */
  13. class BbCode
  14. {
  15. /**
  16. * @var TagInterface[]
  17. */
  18. protected $tags = [];
  19. private $tokenCacheMap = [];
  20. private $allowedChildrenTags = [];
  21. public function addTag(TagInterface $tag) : self
  22. {
  23. $this->tags[] = $tag;
  24. return $this;
  25. }
  26. /**
  27. * @return TagInterface[]
  28. */
  29. public function getTags() : array
  30. {
  31. return $this->tags;
  32. }
  33. public function addAllowedChildTag(TagInterface $root, TagInterface $child) : self
  34. {
  35. if (false === array_key_exists($root->getName(), $this->allowedChildrenTags)) {
  36. $this->allowedChildrenTags[$root->getName()] = [];
  37. }
  38. if (false === array_search($child, $this->allowedChildrenTags[$root->getName()])) {
  39. $this->allowedChildrenTags[$root->getName()][] = $child;
  40. }
  41. return $this;
  42. }
  43. public function getAllowedChildrenTags(TagInterface $tag) : array
  44. {
  45. if (false === array_key_exists($tag->getName(), $this->allowedChildrenTags)) {
  46. return [];
  47. }
  48. return $this->allowedChildrenTags[$tag->getName()];
  49. }
  50. public function format(TokenTag $tokenRootTag, TagBag $allowedTags = null) : string
  51. {
  52. $currentBbCodeType = $this->getBbCodeTagFromTokenTag($tokenRootTag);
  53. $currentElementAllowedTags = $this->getAllowedChildrenTags($currentBbCodeType);
  54. if ($allowedTags === null) {
  55. // get allowedTags from currentBBType
  56. $allowedTagsForChildren = new TagBag($currentElementAllowedTags);
  57. $tagAllowed = true;
  58. } else {
  59. $tagAllowed = $allowedTags->contains($currentBbCodeType);
  60. $allowedTagsForChildren = $allowedTags->intersect($currentElementAllowedTags);
  61. }
  62. $text = '';
  63. foreach ($tokenRootTag->getTags() as $tokenTag) {
  64. $text .= $this->format($tokenTag, $allowedTagsForChildren);
  65. }
  66. $tmpTag = clone $tokenRootTag;
  67. $tmpTag->setText($text . $tokenRootTag->getText());
  68. if ($tagAllowed) {
  69. $textFormatted = $currentBbCodeType->format($tmpTag);
  70. } else {
  71. $textFormatted = $currentBbCodeType->getOriginalText($tmpTag);
  72. }
  73. return $textFormatted;
  74. }
  75. private function getBbCodeTagFromTokenTag(TokenTag $tokenTag) : TagInterface
  76. {
  77. if (array_key_exists($tokenTag->getType(), $this->tags)) {
  78. return new $this->tokenCacheMap[$tokenTag];
  79. }
  80. foreach ($this->tags as $tag) {
  81. if ($tag->getName() === $tokenTag->getType()) {
  82. $this->tokenCacheMap[$tokenTag->getType()] = $tag;
  83. return $tag;
  84. }
  85. }
  86. if ($tokenTag->getType() === null) {
  87. $textTag = new TextTag();
  88. $this->tokenCacheMap[$tokenTag->getType()] = $textTag;
  89. } else {
  90. // convert null to ''
  91. if ($tokenTag->getArgument() !== null) {
  92. $textTag = new UnknownSimpleType($tokenTag->getArgument());
  93. } else {
  94. $textTag = new UnknownSimpleType();
  95. }
  96. $this->tokenCacheMap[$tokenTag->getType()] = $textTag;
  97. }
  98. return $textTag;
  99. }
  100. }