DatagridBuilder.php 7.7 KB

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