DatagridBuilder.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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. namespace Sonata\AdminBundle\Builder\ORM;
  11. use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
  12. use Sonata\AdminBundle\Model\ModelManagerInterface;
  13. use Sonata\AdminBundle\Admin\AdminInterface;
  14. use Sonata\AdminBundle\Datagrid\DatagridInterface;
  15. use Sonata\AdminBundle\Datagrid\Datagrid;
  16. use Sonata\AdminBundle\Datagrid\ORM\Pager;
  17. use Sonata\AdminBundle\Datagrid\ORM\ProxyQuery;
  18. use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
  19. use Symfony\Component\Form\FormFactory;
  20. use Doctrine\ORM\Mapping\ClassMetadataInfo;
  21. class DatagridBuilder implements DatagridBuilderInterface
  22. {
  23. protected $formFactory;
  24. /**
  25. * todo: put this in the DIC
  26. *
  27. * built-in definition
  28. *
  29. * @var array
  30. */
  31. protected $filterClasses = array(
  32. 'string' => 'Sonata\\AdminBundle\\Filter\\ORM\\StringFilter',
  33. 'text' => 'Sonata\\AdminBundle\\Filter\\ORM\\StringFilter',
  34. 'boolean' => 'Sonata\\AdminBundle\\Filter\\ORM\\BooleanFilter',
  35. 'integer' => 'Sonata\\AdminBundle\\Filter\\ORM\\IntegerFilter',
  36. 'tinyint' => 'Sonata\\AdminBundle\\Filter\\ORM\\IntegerFilter',
  37. 'smallint' => 'Sonata\\AdminBundle\\Filter\\ORM\\IntegerFilter',
  38. 'mediumint' => 'Sonata\\AdminBundle\\Filter\\ORM\\IntegerFilter',
  39. 'bigint' => 'Sonata\\AdminBundle\\Filter\\ORM\\IntegerFilter',
  40. 'decimal' => 'Sonata\\AdminBundle\\Filter\\ORM\\IntegerFilter',
  41. 'callback' => 'Sonata\\AdminBundle\\Filter\\ORM\\CallbackFilter',
  42. 'choice' => 'Sonata\\AdminBundle\\Filter\\ORM\\ChoiceFilter',
  43. );
  44. public function __construct(FormFactory $formFactory)
  45. {
  46. $this->formFactory = $formFactory;
  47. }
  48. /**
  49. * @throws \RuntimeException
  50. * @param \Sonata\AdminBundle\Admin\AdminInterface $admin
  51. * @param \Sonata\AdminBundle\Admin\FieldDescription $fieldDescription
  52. * @return void
  53. */
  54. public function fixFieldDescription(AdminInterface $admin, FieldDescriptionInterface $fieldDescription)
  55. {
  56. // set default values
  57. $fieldDescription->setAdmin($admin);
  58. if ($admin->getModelManager()->hasMetadata($admin->getClass())) {
  59. $metadata = $admin->getModelManager()->getMetadata($admin->getClass());
  60. // set the default field mapping
  61. if (isset($metadata->fieldMappings[$fieldDescription->getName()])) {
  62. $fieldDescription->setFieldMapping($metadata->fieldMappings[$fieldDescription->getName()]);
  63. }
  64. // set the default association mapping
  65. if (isset($metadata->associationMappings[$fieldDescription->getName()])) {
  66. $fieldDescription->setAssociationMapping($metadata->associationMappings[$fieldDescription->getName()]);
  67. }
  68. }
  69. if (!$fieldDescription->getType()) {
  70. throw new \RuntimeException(sprintf('Please define a type for field `%s` in `%s`', $fieldDescription->getName(), get_class($admin)));
  71. }
  72. $fieldDescription->setOption('code', $fieldDescription->getOption('code', $fieldDescription->getName()));
  73. $fieldDescription->setOption('label', $fieldDescription->getOption('label', $fieldDescription->getName()));
  74. $fieldDescription->setOption('filter_value', $fieldDescription->getOption('filter_value', null));
  75. $fieldDescription->setOption('filter_options', $fieldDescription->getOption('filter_options', null));
  76. $fieldDescription->setOption('filter_field_options', $fieldDescription->getOption('filter_field_options', null));
  77. $fieldDescription->setOption('name', $fieldDescription->getOption('name', $fieldDescription->getName()));
  78. // set the default type if none is set
  79. if (!$fieldDescription->getType()) {
  80. $fieldDescription->setType('string');
  81. }
  82. if (!$fieldDescription->getTemplate()) {
  83. $fieldDescription->setTemplate(sprintf('SonataAdminBundle:CRUD:filter_%s.html.twig', $fieldDescription->getType()));
  84. if ($fieldDescription->getType() == ClassMetadataInfo::MANY_TO_ONE) {
  85. $fieldDescription->setTemplate('SonataAdminBundle:CRUD:filter_many_to_one.html.twig');
  86. }
  87. if ($fieldDescription->getType() == ClassMetadataInfo::MANY_TO_MANY) {
  88. $fieldDescription->setTemplate('SonataAdminBundle:CRUD:filter_many_to_many.html.twig');
  89. }
  90. }
  91. }
  92. /**
  93. * return the class associated to a FieldDescription if any defined
  94. *
  95. * @throws RuntimeException
  96. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  97. * @return bool|string
  98. */
  99. public function getFilterFieldClass(FieldDescriptionInterface $fieldDescription)
  100. {
  101. if ($fieldDescription->getOption('filter_field_widget', false)) {
  102. $class = $fieldDescription->getOption('filter_field_widget', false);
  103. } else {
  104. $class = array_key_exists($fieldDescription->getType(), $this->filterClasses) ? $this->filterClasses[$fieldDescription->getType()] : false;
  105. }
  106. if (!class_exists($class)) {
  107. throw new \RuntimeException(sprintf('The class `%s` does not exist for field `%s`', $class, $fieldDescription->getType()));
  108. }
  109. return $class;
  110. }
  111. /**
  112. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  113. * @return array
  114. */
  115. public function getChoices(FieldDescriptionInterface $fieldDescription)
  116. {
  117. $modelManager = $fieldDescription->getAdmin()->getModelManager();
  118. $targets = $modelManager->getEntityManager()
  119. ->createQueryBuilder()
  120. ->select('t')
  121. ->from($fieldDescription->getTargetEntity(), 't')
  122. ->getQuery()
  123. ->execute();
  124. $choices = array();
  125. foreach ($targets as $target) {
  126. // todo : puts this into a configuration option and use reflection
  127. foreach (array('getTitle', 'getName', '__toString') as $getter) {
  128. if (method_exists($target, $getter)) {
  129. $choices[$modelManager->getNormalizedIdentifier($target)] = $target->$getter();
  130. break;
  131. }
  132. }
  133. }
  134. return $choices;
  135. }
  136. /**
  137. * @param \Sonata\AdminBundle\Datagrid\DatagridInterface $datagrid
  138. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  139. * @return bool
  140. */
  141. public function addFilter(DatagridInterface $datagrid, $type = null, FieldDescriptionInterface $fieldDescription, AdminInterface $admin)
  142. {
  143. if ($type == null) {
  144. throw new \RunTimeException('type guesser on DatagridBuilder is not yet implemented');
  145. }
  146. $fieldDescription->setType($type);
  147. $this->fixFieldDescription($admin, $fieldDescription);
  148. $admin->addFilterFieldDescription($fieldDescription->getName(), $fieldDescription);
  149. switch($fieldDescription->getMappingType()) {
  150. case ClassMetadataInfo::MANY_TO_ONE:
  151. $options = $fieldDescription->getOption('filter_field_options');
  152. $filter = new \Sonata\AdminBundle\Filter\ORM\IntegerFilter($fieldDescription);
  153. break;
  154. case ClassMetadataInfo::MANY_TO_MANY:
  155. $options = $fieldDescription->getOption('filter_field_options');
  156. $options['choices'] = $this->getChoices($fieldDescription);
  157. $fieldDescription->setOption('filter_field_options', $options);
  158. $filter = new \Sonata\AdminBundle\Filter\ORM\ChoiceFilter($fieldDescription);
  159. break;
  160. default:
  161. $class = $this->getFilterFieldClass($fieldDescription);
  162. $filter = new $class($fieldDescription);
  163. }
  164. return $datagrid->addFilter($filter);
  165. }
  166. /**
  167. * @param \Sonata\AdminBundle\Admin\AdminInterface $admin
  168. * @param array $values
  169. * @return \Sonata\AdminBundle\Datagrid\DatagridInterface
  170. */
  171. public function getBaseDatagrid(AdminInterface $admin, array $values = array())
  172. {
  173. $queryBuilder = $admin->getModelManager()->createQuery($admin->getClass());
  174. $query = new ProxyQuery($queryBuilder);
  175. $pager = new Pager;
  176. $pager->setCountColumn($admin->getModelManager()->getIdentifierFieldNames($admin->getClass()));
  177. return new Datagrid(
  178. $query,
  179. $admin->getList(),
  180. $pager,
  181. $this->formFactory,
  182. $values
  183. );
  184. }
  185. }