SectionManager.php 4.7 KB

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