BaseGroupedMapper.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. * This class is used to simulate the Form API.
  13. */
  14. abstract class BaseGroupedMapper extends BaseMapper
  15. {
  16. protected $currentGroup;
  17. protected $currentTab;
  18. abstract protected function getGroups();
  19. abstract protected function getTabs();
  20. abstract protected function setGroups(array $groups);
  21. abstract protected function setTabs(array $tabs);
  22. /**
  23. * Add new group or tab (if parameter "tab=true" is available in options).
  24. *
  25. * @param string $name
  26. * @param array $options
  27. *
  28. * @return $this
  29. *
  30. * @throws \RuntimeException
  31. */
  32. public function with($name, array $options = array())
  33. {
  34. /*
  35. * The current implementation should work with the following workflow:
  36. *
  37. * $formMapper
  38. * ->with('group1')
  39. * ->add('username')
  40. * ->add('password')
  41. * ->end()
  42. * ->with('tab1', array('tab' => true))
  43. * ->with('group1')
  44. * ->add('username')
  45. * ->add('password')
  46. * ->end()
  47. * ->with('group2', array('collapsed' => true))
  48. * ->add('enabled')
  49. * ->add('createdAt')
  50. * ->end()
  51. * ->end();
  52. *
  53. */
  54. $defaultOptions = array(
  55. 'collapsed' => false,
  56. 'class' => false,
  57. 'description' => false,
  58. 'translation_domain' => null,
  59. 'name' => $name,
  60. );
  61. $code = $name;
  62. // Open
  63. if (array_key_exists('tab', $options) && $options['tab']) {
  64. $tabs = $this->getTabs();
  65. if ($this->currentTab) {
  66. if (isset($tabs[$this->currentTab]['auto_created']) && true === $tabs[$this->currentTab]['auto_created']) {
  67. 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.');
  68. } else {
  69. throw new \RuntimeException(sprintf('You should close previous tab "%s" with end() before adding new tab "%s".', $this->currentTab, $name));
  70. }
  71. } elseif ($this->currentGroup) {
  72. throw new \RuntimeException(sprintf('You should open tab before adding new group "%s".', $name));
  73. }
  74. if (!isset($tabs[$name])) {
  75. $tabs[$name] = array();
  76. }
  77. $tabs[$code] = array_merge($defaultOptions, array(
  78. 'auto_created' => false,
  79. 'groups' => array(),
  80. ), $tabs[$code], $options);
  81. $this->currentTab = $code;
  82. } else {
  83. if ($this->currentGroup) {
  84. throw new \RuntimeException(sprintf('You should close previous group "%s" with end() before adding new tab "%s".', $this->currentGroup, $name));
  85. }
  86. if (!$this->currentTab) {
  87. // no tab define
  88. $this->with('default', array(
  89. 'tab' => true,
  90. 'auto_created' => true,
  91. 'translation_domain' => isset($options['translation_domain']) ? $options['translation_domain'] : null,
  92. )); // add new tab automatically
  93. }
  94. // if no tab is selected, we go the the main one named '_' ..
  95. if ($this->currentTab !== 'default') {
  96. $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
  97. }
  98. $groups = $this->getGroups();
  99. if (!isset($groups[$code])) {
  100. $groups[$code] = array();
  101. }
  102. $groups[$code] = array_merge($defaultOptions, array(
  103. 'fields' => array(),
  104. ), $groups[$code], $options);
  105. $this->currentGroup = $code;
  106. $this->setGroups($groups);
  107. $tabs = $this->getTabs();
  108. }
  109. if ($this->currentGroup && isset($tabs[$this->currentTab]) && !in_array($this->currentGroup, $tabs[$this->currentTab]['groups'])) {
  110. $tabs[$this->currentTab]['groups'][] = $this->currentGroup;
  111. }
  112. $this->setTabs($tabs);
  113. return $this;
  114. }
  115. /**
  116. * Add new tab.
  117. *
  118. * @param string $name
  119. * @param array $options
  120. *
  121. * @return $this
  122. */
  123. public function tab($name, array $options = array())
  124. {
  125. return $this->with($name, array_merge($options, array('tab' => true)));
  126. }
  127. /**
  128. * Close the current group or tab.
  129. *
  130. * @return $this
  131. *
  132. * @throws \RuntimeException
  133. */
  134. public function end()
  135. {
  136. if ($this->currentGroup !== null) {
  137. $this->currentGroup = null;
  138. } elseif ($this->currentTab !== null) {
  139. $this->currentTab = null;
  140. } else {
  141. throw new \RuntimeException('No open tabs or groups, you cannot use end()');
  142. }
  143. return $this;
  144. }
  145. /**
  146. * Add the field name to the current group.
  147. *
  148. * @param string $fieldName
  149. */
  150. protected function addFieldToCurrentGroup($fieldName)
  151. {
  152. // Note this line must happen before the next line.
  153. // See https://github.com/sonata-project/SonataAdminBundle/pull/1351
  154. $currentGroup = $this->getCurrentGroupName();
  155. $groups = $this->getGroups();
  156. $groups[$currentGroup]['fields'][$fieldName] = $fieldName;
  157. $this->setGroups($groups);
  158. return $groups[$currentGroup];
  159. }
  160. /**
  161. * Return the name of the currently selected group. The method also makes
  162. * sure a valid group name is currently selected.
  163. *
  164. * Note that this can have the side effect to change the 'group' value
  165. * returned by the getGroup function
  166. *
  167. * @return string
  168. */
  169. protected function getCurrentGroupName()
  170. {
  171. if (!$this->currentGroup) {
  172. $this->with($this->admin->getLabel(), array('auto_created' => true));
  173. }
  174. return $this->currentGroup;
  175. }
  176. }