ManagesLayouts.php 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. namespace Illuminate\View\Concerns;
  3. use InvalidArgumentException;
  4. use Illuminate\Contracts\View\View;
  5. trait ManagesLayouts
  6. {
  7. /**
  8. * All of the finished, captured sections.
  9. *
  10. * @var array
  11. */
  12. protected $sections = [];
  13. /**
  14. * The stack of in-progress sections.
  15. *
  16. * @var array
  17. */
  18. protected $sectionStack = [];
  19. /**
  20. * The parent placeholder for the request.
  21. *
  22. * @var mixed
  23. */
  24. protected static $parentPlaceholder = [];
  25. /**
  26. * Start injecting content into a section.
  27. *
  28. * @param string $section
  29. * @param string|null $content
  30. * @return void
  31. */
  32. public function startSection($section, $content = null)
  33. {
  34. if ($content === null) {
  35. if (ob_start()) {
  36. $this->sectionStack[] = $section;
  37. }
  38. } else {
  39. $this->extendSection($section, $content instanceof View ? $content : e($content));
  40. }
  41. }
  42. /**
  43. * Inject inline content into a section.
  44. *
  45. * @param string $section
  46. * @param string $content
  47. * @return void
  48. */
  49. public function inject($section, $content)
  50. {
  51. $this->startSection($section, $content);
  52. }
  53. /**
  54. * Stop injecting content into a section and return its contents.
  55. *
  56. * @return string
  57. */
  58. public function yieldSection()
  59. {
  60. if (empty($this->sectionStack)) {
  61. return '';
  62. }
  63. return $this->yieldContent($this->stopSection());
  64. }
  65. /**
  66. * Stop injecting content into a section.
  67. *
  68. * @param bool $overwrite
  69. * @return string
  70. * @throws \InvalidArgumentException
  71. */
  72. public function stopSection($overwrite = false)
  73. {
  74. if (empty($this->sectionStack)) {
  75. throw new InvalidArgumentException('Cannot end a section without first starting one.');
  76. }
  77. $last = array_pop($this->sectionStack);
  78. if ($overwrite) {
  79. $this->sections[$last] = ob_get_clean();
  80. } else {
  81. $this->extendSection($last, ob_get_clean());
  82. }
  83. return $last;
  84. }
  85. /**
  86. * Stop injecting content into a section and append it.
  87. *
  88. * @return string
  89. * @throws \InvalidArgumentException
  90. */
  91. public function appendSection()
  92. {
  93. if (empty($this->sectionStack)) {
  94. throw new InvalidArgumentException('Cannot end a section without first starting one.');
  95. }
  96. $last = array_pop($this->sectionStack);
  97. if (isset($this->sections[$last])) {
  98. $this->sections[$last] .= ob_get_clean();
  99. } else {
  100. $this->sections[$last] = ob_get_clean();
  101. }
  102. return $last;
  103. }
  104. /**
  105. * Append content to a given section.
  106. *
  107. * @param string $section
  108. * @param string $content
  109. * @return void
  110. */
  111. protected function extendSection($section, $content)
  112. {
  113. if (isset($this->sections[$section])) {
  114. $content = str_replace(static::parentPlaceholder($section), $content, $this->sections[$section]);
  115. }
  116. $this->sections[$section] = $content;
  117. }
  118. /**
  119. * Get the string contents of a section.
  120. *
  121. * @param string $section
  122. * @param string $default
  123. * @return string
  124. */
  125. public function yieldContent($section, $default = '')
  126. {
  127. $sectionContent = $default instanceof View ? $default : e($default);
  128. if (isset($this->sections[$section])) {
  129. $sectionContent = $this->sections[$section];
  130. }
  131. $sectionContent = str_replace('@@parent', '--parent--holder--', $sectionContent);
  132. return str_replace(
  133. '--parent--holder--', '@parent', str_replace(static::parentPlaceholder($section), '', $sectionContent)
  134. );
  135. }
  136. /**
  137. * Get the parent placeholder for the current request.
  138. *
  139. * @param string $section
  140. * @return string
  141. */
  142. public static function parentPlaceholder($section = '')
  143. {
  144. if (! isset(static::$parentPlaceholder[$section])) {
  145. static::$parentPlaceholder[$section] = '##parent-placeholder-'.sha1($section).'##';
  146. }
  147. return static::$parentPlaceholder[$section];
  148. }
  149. /**
  150. * Check if section exists.
  151. *
  152. * @param string $name
  153. * @return bool
  154. */
  155. public function hasSection($name)
  156. {
  157. return array_key_exists($name, $this->sections);
  158. }
  159. /**
  160. * Get the contents of a section.
  161. *
  162. * @param string $name
  163. * @param string $default
  164. * @return mixed
  165. */
  166. public function getSection($name, $default = null)
  167. {
  168. return $this->getSections()[$name] ?? $default;
  169. }
  170. /**
  171. * Get the entire array of sections.
  172. *
  173. * @return array
  174. */
  175. public function getSections()
  176. {
  177. return $this->sections;
  178. }
  179. /**
  180. * Flush all of the sections.
  181. *
  182. * @return void
  183. */
  184. public function flushSections()
  185. {
  186. $this->sections = [];
  187. $this->sectionStack = [];
  188. }
  189. }