BaseGroupedMapper.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <?php
  2. /*
  3. * This file is part of the Sonata Project package.
  4. *
  5. * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Sonata\AdminBundle\Mapper;
  11. /**
  12. * Class BaseGroupedMapper
  13. * This class is used to simulate the Form API.
  14. *
  15. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  16. */
  17. abstract class BaseGroupedMapper extends BaseMapper
  18. {
  19. /**
  20. * @var string
  21. */
  22. protected $currentGroup;
  23. /**
  24. * @var string
  25. */
  26. protected $currentTab;
  27. /**
  28. * @var bool
  29. */
  30. protected $apply;
  31. /**
  32. * Add new group or tab (if parameter "tab=true" is available in options).
  33. *
  34. * @param string $name
  35. * @param array $options
  36. *
  37. * @return $this
  38. *
  39. * @throws \RuntimeException
  40. */
  41. public function with($name, array $options = array())
  42. {
  43. /*
  44. * The current implementation should work with the following workflow:
  45. *
  46. * $formMapper
  47. * ->with('group1')
  48. * ->add('username')
  49. * ->add('password')
  50. * ->end()
  51. * ->with('tab1', array('tab' => true))
  52. * ->with('group1')
  53. * ->add('username')
  54. * ->add('password')
  55. * ->end()
  56. * ->with('group2', array('collapsed' => true))
  57. * ->add('enabled')
  58. * ->add('createdAt')
  59. * ->end()
  60. * ->end();
  61. *
  62. */
  63. $defaultOptions = array(
  64. 'collapsed' => false,
  65. 'class' => false,
  66. 'description' => false,
  67. 'translation_domain' => null,
  68. 'name' => $name,
  69. 'box_class' => 'box box-primary',
  70. );
  71. $code = $name;
  72. // Open
  73. if (array_key_exists('tab', $options) && $options['tab']) {
  74. $tabs = $this->getTabs();
  75. if ($this->currentTab) {
  76. if (isset($tabs[$this->currentTab]['auto_created']) && true === $tabs[$this->currentTab]['auto_created']) {
  77. throw new \RuntimeException('New tab was added automatically when you have added field or group. You should close current tab before adding new one OR add tabs before adding groups and fields.');
  78. } else {
  79. throw new \RuntimeException(sprintf('You should close previous tab "%s" with end() before adding new tab "%s".', $this->currentTab, $name));
  80. }
  81. } elseif ($this->currentGroup) {
  82. throw new \RuntimeException(sprintf('You should open tab before adding new group "%s".', $name));
  83. }
  84. if (!isset($tabs[$name])) {
  85. $tabs[$name] = array();
  86. }
  87. $tabs[$code] = array_merge($defaultOptions, array(
  88. 'auto_created' => false,
  89. 'groups' => array(),
  90. ), $tabs[$code], $options);
  91. $this->currentTab = $code;
  92. } else {
  93. if ($this->currentGroup) {
  94. throw new \RuntimeException(sprintf('You should close previous group "%s" with end() before adding new tab "%s".', $this->currentGroup, $name));
  95. }
  96. if (!$this->currentTab) {
  97. // no tab define
  98. $this->with('default', array(
  99. 'tab' => true,
  100. 'auto_created' => true,
  101. 'translation_domain' => isset($options['translation_domain']) ? $options['translation_domain'] : null,
  102. )); // add new tab automatically
  103. }
  104. // if no tab is selected, we go the the main one named '_' ..
  105. if ($this->currentTab !== 'default') {
  106. $code = $this->currentTab.'.'.$name; // groups with the same name can be on different tabs, so we prefix them in order to make unique group name
  107. }
  108. $groups = $this->getGroups();
  109. if (!isset($groups[$code])) {
  110. $groups[$code] = array();
  111. }
  112. $groups[$code] = array_merge($defaultOptions, array(
  113. 'fields' => array(),
  114. ), $groups[$code], $options);
  115. $this->currentGroup = $code;
  116. $this->setGroups($groups);
  117. $tabs = $this->getTabs();
  118. }
  119. if ($this->currentGroup && isset($tabs[$this->currentTab]) && !in_array($this->currentGroup, $tabs[$this->currentTab]['groups'])) {
  120. $tabs[$this->currentTab]['groups'][] = $this->currentGroup;
  121. }
  122. $this->setTabs($tabs);
  123. return $this;
  124. }
  125. /**
  126. * Only nested add if the condition match true.
  127. *
  128. * @param bool $bool
  129. *
  130. * @return $this
  131. *
  132. * @throws \RuntimeException
  133. */
  134. public function ifTrue($bool)
  135. {
  136. if ($this->apply !== null) {
  137. throw new \RuntimeException('Cannot nest ifTrue or ifFalse call');
  138. }
  139. $this->apply = ($bool === true);
  140. return $this;
  141. }
  142. /**
  143. * Only nested add if the condition match false.
  144. *
  145. * @param bool $bool
  146. *
  147. * @return $this
  148. *
  149. * @throws \RuntimeException
  150. */
  151. public function ifFalse($bool)
  152. {
  153. if ($this->apply !== null) {
  154. throw new \RuntimeException('Cannot nest ifTrue or ifFalse call');
  155. }
  156. $this->apply = ($bool === false);
  157. return $this;
  158. }
  159. /**
  160. * @return $this
  161. */
  162. public function ifEnd()
  163. {
  164. $this->apply = null;
  165. return $this;
  166. }
  167. /**
  168. * Add new tab.
  169. *
  170. * @param string $name
  171. * @param array $options
  172. *
  173. * @return $this
  174. */
  175. public function tab($name, array $options = array())
  176. {
  177. return $this->with($name, array_merge($options, array('tab' => true)));
  178. }
  179. /**
  180. * Close the current group or tab.
  181. *
  182. * @return $this
  183. *
  184. * @throws \RuntimeException
  185. */
  186. public function end()
  187. {
  188. if ($this->currentGroup !== null) {
  189. $this->currentGroup = null;
  190. } elseif ($this->currentTab !== null) {
  191. $this->currentTab = null;
  192. } else {
  193. throw new \RuntimeException('No open tabs or groups, you cannot use end()');
  194. }
  195. return $this;
  196. }
  197. /**
  198. * Returns a boolean indicating if there is an open tab at the moment.
  199. *
  200. * @return bool
  201. */
  202. public function hasOpenTab()
  203. {
  204. return null !== $this->currentTab;
  205. }
  206. /**
  207. * @return array
  208. */
  209. abstract protected function getGroups();
  210. /**
  211. * @return array
  212. */
  213. abstract protected function getTabs();
  214. /**
  215. * @param array $groups
  216. */
  217. abstract protected function setGroups(array $groups);
  218. /**
  219. * @param array $tabs
  220. */
  221. abstract protected function setTabs(array $tabs);
  222. /**
  223. * Add the field name to the current group.
  224. *
  225. * @param string $fieldName
  226. */
  227. protected function addFieldToCurrentGroup($fieldName)
  228. {
  229. // Note this line must happen before the next line.
  230. // See https://github.com/sonata-project/SonataAdminBundle/pull/1351
  231. $currentGroup = $this->getCurrentGroupName();
  232. $groups = $this->getGroups();
  233. $groups[$currentGroup]['fields'][$fieldName] = $fieldName;
  234. $this->setGroups($groups);
  235. return $groups[$currentGroup];
  236. }
  237. /**
  238. * Return the name of the currently selected group. The method also makes
  239. * sure a valid group name is currently selected.
  240. *
  241. * Note that this can have the side effect to change the 'group' value
  242. * returned by the getGroup function
  243. *
  244. * @return string
  245. */
  246. protected function getCurrentGroupName()
  247. {
  248. if (!$this->currentGroup) {
  249. $this->with($this->admin->getLabel(), array('auto_created' => true));
  250. }
  251. return $this->currentGroup;
  252. }
  253. }