BlockLayoutBuilderTrait.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <?php
  2. namespace App\Support\Traits;
  3. use DOMElement;
  4. /*
  5. * Трейт: построение результирующего массива (fields + blade) для плоской
  6. * структуры и для repeater-структуры.
  7. * Используется классом BlockLayoutParser.
  8. */
  9. trait BlockLayoutBuilderTrait
  10. {
  11. // ── Плоская структура ─────────────────────────────────────────────────
  12. private function buildFlat(DOMElement $wrapper): array
  13. {
  14. $raw = [];
  15. foreach ($this->elementChildren($wrapper) as $child) {
  16. $this->extractFields($child, $raw, '$data');
  17. }
  18. $this->applyTokens($raw);
  19. $blade = $this->serializeChildren($wrapper);
  20. $blade = $this->replaceTokens($blade);
  21. $fields = $this->publicFields($raw);
  22. return ['fields' => $fields, 'blade' => $blade, 'is_repeater' => false];
  23. }
  24. // ── Repeater ──────────────────────────────────────────────────────────
  25. private function buildRepeater(DOMElement $wrapper, DOMElement $container, array $items): array
  26. {
  27. // Sub-fields извлекаем из первого элемента-образца
  28. $rawSub = [];
  29. $this->extractFields($items[0], $rawSub, '$item');
  30. $this->applyTokens($rawSub);
  31. // Blade для одного item
  32. $itemBlade = $this->dom->saveHTML($items[0]);
  33. $itemBlade = $this->replaceTokens($itemBlade);
  34. // Блок @foreach
  35. $foreachBlock = "@foreach(\$data['items'] as \$item)\n "
  36. . str_replace("\n", "\n ", trim($itemBlade))
  37. . "\n@endforeach";
  38. if ($container === $wrapper) {
  39. $blade = $foreachBlock;
  40. } else {
  41. // container — один из потомков wrapper;
  42. // удаляем лишние item-дублёры, оставляем placeholder @foreach
  43. foreach (array_slice($items, 1) as $item) {
  44. $container->removeChild($item);
  45. }
  46. $foreachToken = 'BLADEFOREACHBLOCK';
  47. $this->tokens[$foreachToken] = $foreachBlock;
  48. $container->replaceChild(
  49. $this->dom->createTextNode($foreachToken),
  50. $items[0]
  51. );
  52. // Также ищем плоские поля в частях wrapper вне container
  53. $outerRaw = [];
  54. foreach ($this->elementChildren($wrapper) as $child) {
  55. if ($child !== $container) {
  56. $this->extractFields($child, $outerRaw, '$data');
  57. }
  58. }
  59. $this->applyTokens($outerRaw);
  60. $blade = $this->serializeChildren($wrapper);
  61. $blade = $this->replaceTokens($blade);
  62. $outerFields = $this->publicFields($outerRaw);
  63. $fields = array_merge($outerFields, [[
  64. 'name' => 'items',
  65. 'label' => 'Элементы',
  66. 'type' => 'repeater',
  67. 'sub_fields' => $this->publicFields($rawSub),
  68. ]]);
  69. return ['fields' => $fields, 'blade' => $blade, 'is_repeater' => true];
  70. }
  71. $fields = [[
  72. 'name' => 'items',
  73. 'label' => 'Элементы',
  74. 'type' => 'repeater',
  75. 'sub_fields' => $this->publicFields($rawSub),
  76. ]];
  77. return ['fields' => $fields, 'blade' => $blade, 'is_repeater' => true];
  78. }
  79. }