BaseGroupedMapper.php 7.6 KB

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