SectionManager.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. namespace Dcat\Admin\Layout;
  3. use Dcat\Admin\Support\Helper;
  4. use Illuminate\Support\Fluent;
  5. use InvalidArgumentException;
  6. use Illuminate\Contracts\View\View;
  7. use Illuminate\Contracts\Support\Renderable;
  8. use Illuminate\Contracts\Support\Htmlable;
  9. class SectionManager
  10. {
  11. /**
  12. * All of the finished, captured sections.
  13. *
  14. * @var array
  15. */
  16. protected $sections = [];
  17. /**
  18. * @var array
  19. */
  20. protected $sortedSections = [];
  21. /**
  22. * @var array
  23. */
  24. protected $defaultSections = [];
  25. /**
  26. * Inject content into a section.
  27. *
  28. * @param string $section
  29. * @param string|Renderable|Htmlable|callable $content
  30. * @param bool $append
  31. * @param int $priority
  32. * @return void
  33. */
  34. public function inject($section, $content, bool $append = true, int $priority = 10)
  35. {
  36. $this->put($section, $content, $append, $priority);
  37. }
  38. /**
  39. * @param string $section
  40. * @param string|Renderable|Htmlable|callable $content
  41. * @return void
  42. */
  43. public function injectDefault($section, $content)
  44. {
  45. if ($this->hasSection($section)) {
  46. return;
  47. }
  48. $this->defaultSections[$section] = &$content;
  49. }
  50. /**
  51. * Set content to a given section.
  52. *
  53. * @param string $section
  54. * @param string|Renderable|Htmlable|callable $content
  55. * @param bool $append
  56. * @param int $priority
  57. * @return void
  58. */
  59. protected function put($section, $content, bool $append = false, int $priority = 10)
  60. {
  61. if (! $section) {
  62. throw new \InvalidArgumentException("Section name is required.");
  63. }
  64. if (! isset($this->sections[$section])) {
  65. unset($this->defaultSections[$section]);
  66. $this->sections[$section] = [];
  67. }
  68. if (! isset($this->sections[$section][$priority])) {
  69. $this->sections[$section][$priority] = [];
  70. }
  71. $this->sections[$section][$priority][] = [
  72. 'append' => $append,
  73. 'value' => &$content,
  74. ];
  75. }
  76. /**
  77. * Get the string contents of a section.
  78. *
  79. * @param $section
  80. * @param string $default
  81. * @param array $options
  82. * @return string
  83. */
  84. public function yieldContent($section, $default = '', array $options = [])
  85. {
  86. $defaultSection = $this->defaultSections[$section] ?? null;
  87. if (! $this->hasSection($section) && $defaultSection === null) {
  88. return Helper::render($default, [new Fluent()]);
  89. }
  90. $content = $this->getSections($section) ?: $defaultSection;
  91. return $this->resolveContent($section, $content, $options);
  92. }
  93. /**
  94. * Get all of the sections for a given name.
  95. *
  96. * @param string $name
  97. * @return array
  98. */
  99. public function getSections($name)
  100. {
  101. $this->sortSections($name);
  102. return $this->sortedSections[$name];
  103. }
  104. /**
  105. * Sort the listeners for a given event by priority.
  106. *
  107. * @param string $name
  108. * @return array
  109. */
  110. protected function sortSections($name)
  111. {
  112. $this->sortedSections[$name] = [];
  113. if (! empty($this->sections[$name])) {
  114. krsort($this->sections[$name]);
  115. $this->sortedSections[$name] = call_user_func_array(
  116. 'array_merge', $this->sections[$name]
  117. );
  118. }
  119. }
  120. /**
  121. * Check if section exists.
  122. *
  123. * @param string $name
  124. * @return bool
  125. */
  126. public function hasSection($name)
  127. {
  128. return array_key_exists($name, $this->sections);
  129. }
  130. /**
  131. * Check if default section exists.
  132. *
  133. * @param string $name
  134. * @return bool
  135. */
  136. public function hasDefaultSection($name)
  137. {
  138. return array_key_exists($name, $this->defaultSections);
  139. }
  140. /**
  141. * @param $name
  142. * @param $content
  143. * @param array $options
  144. * @return string
  145. */
  146. protected function resolveContent($name, &$content, array &$options)
  147. {
  148. if (is_string($content)) {
  149. return $content;
  150. }
  151. if (!is_array($content)) {
  152. $content = [['append' => true, 'value' => $content]];
  153. }
  154. $options = new Fluent($options);
  155. $options->previous = '';
  156. $result = '';
  157. foreach ($content as &$item) {
  158. $value = Helper::render($item['value'] ?? '', [$options]);
  159. $append = $item['append'] ?? false;
  160. if (!$append) {
  161. $result = '';
  162. }
  163. $result .= $value;
  164. $options->previous = $result;
  165. }
  166. // $this->sections[$name] = [['value' => &$result]];
  167. return $result;
  168. }
  169. /**
  170. * Flush all of the sections.
  171. *
  172. * @return void
  173. */
  174. public function flushSections()
  175. {
  176. $this->sections = [];
  177. $this->defaultSections = [];
  178. }
  179. }