SonataAdminExtension.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. <?php
  2. /*
  3. * This file is part of sonata-project.
  4. *
  5. * (c) 2010 Thomas Rabaix
  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\Twig\Extension;
  11. use Sonata\AdminBundle\Admin\FieldDescriptionInterface;
  12. use Sonata\AdminBundle\Filter\FilterInterface;
  13. use Sonata\AdminBundle\Admin\NoValueException;
  14. use Symfony\Component\Form\FormView;
  15. class SonataAdminExtension extends \Twig_Extension
  16. {
  17. /**
  18. * @var \Twig_Environment
  19. */
  20. protected $environment;
  21. /**
  22. * {@inheritdoc}
  23. */
  24. public function initRuntime(\Twig_Environment $environment)
  25. {
  26. $this->environment = $environment;
  27. }
  28. /**
  29. * Returns a list of filters to add to the existing list.
  30. *
  31. * @return array An array of filters
  32. */
  33. public function getFilters()
  34. {
  35. return array(
  36. 'render_list_element' => new \Twig_Filter_Method($this, 'renderListElement', array('is_safe' => array('html'))),
  37. 'render_form_element' => new \Twig_Filter_Method($this, 'renderFormElement', array('is_safe' => array('html'))),
  38. 'render_filter_element' => new \Twig_Filter_Method($this, 'renderFilterElement', array('is_safe' => array('html'))),
  39. 'render_view_element' => new \Twig_Filter_Method($this, 'renderViewElement', array('is_safe' => array('html'))),
  40. 'render_relation_element' => new \Twig_Filter_Method($this, 'renderRelationElement', array('is_safe' => array('html'))),
  41. );
  42. }
  43. public function getTokenParsers()
  44. {
  45. return array();
  46. }
  47. /**
  48. * Returns the name of the extension.
  49. *
  50. * @return string The extension name
  51. */
  52. public function getName()
  53. {
  54. return 'sonata_admin';
  55. }
  56. /**
  57. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  58. * @param string $default
  59. * @return \Twig_TemplateInterface
  60. */
  61. protected function getTemplate(FieldDescriptionInterface $fieldDescription, $default)
  62. {
  63. // todo: find a better solution
  64. try {
  65. $template = $this->environment->loadTemplate($fieldDescription->getTemplate());
  66. } catch(\Twig_Error_Loader $e) {
  67. $template = $this->environment->loadTemplate($default);
  68. }
  69. return $template;
  70. }
  71. /**
  72. * render a list element from the FieldDescription
  73. *
  74. * @param mixed $object
  75. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  76. * @param array $params
  77. * @return
  78. */
  79. public function renderListElement($object, FieldDescriptionInterface $fieldDescription, $params = array())
  80. {
  81. $template = $this->getTemplate($fieldDescription, 'SonataAdminBundle:CRUD:base_list.html.twig');
  82. return $this->output($fieldDescription, $template, array_merge($params, array(
  83. 'admin' => $fieldDescription->getAdmin(),
  84. 'object' => $object,
  85. 'value' => $this->getValueFromFieldDescription($object, $fieldDescription),
  86. 'field_description' => $fieldDescription
  87. )));
  88. }
  89. /**
  90. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  91. * @param string $content
  92. * @return string
  93. */
  94. public function output(FieldDescriptionInterface $fieldDescription, \Twig_TemplateInterface $template, array $parameters = array())
  95. {
  96. $content = $template->render($parameters);
  97. if ($this->environment->isDebug()) {
  98. return sprintf("\n<!-- START \n fieldName: %s\n template: %s\n compiled template: %s\n -->\n%s\n<!-- END - fieldName: %s -->",
  99. $fieldDescription->getFieldName(),
  100. $fieldDescription->getTemplate(),
  101. $template->getTemplateName(),
  102. $content,
  103. $fieldDescription->getFieldName()
  104. );
  105. }
  106. return $content;
  107. }
  108. /**
  109. * return the value related to FieldDescription, if the associated object does no
  110. * exists => a temporary one is created
  111. *
  112. * @param object $object
  113. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  114. * @param array $params
  115. * @return mixed
  116. */
  117. public function getValueFromFieldDescription($object, FieldDescriptionInterface $fieldDescription, array $params = array())
  118. {
  119. if (isset($params['loop']) && $object instanceof \ArrayAccess) {
  120. throw new \RuntimeException('remove the loop requirement');
  121. }
  122. $value = null;
  123. try {
  124. $value = $fieldDescription->getValue($object);
  125. } catch (NoValueException $e) {
  126. if ($fieldDescription->getAssociationAdmin()) {
  127. $value = $fieldDescription->getAssociationAdmin()->getNewInstance();
  128. }
  129. }
  130. return $value;
  131. }
  132. /**
  133. * render a filter element
  134. *
  135. * @param \Sonata\AdminBundle\Filter\FilterInterface $filter
  136. * @param array $params
  137. * @return string
  138. */
  139. public function renderFilterElement(FilterInterface $filter, array $params = array())
  140. {
  141. $fieldDescription = $filter->getFieldDescription();
  142. $template = $this->getTemplate($fieldDescription, 'SonataAdminBundle:CRUD:base_filter_field.html.twig');
  143. return $this->output($fieldDescription, $template, array_merge($params, array(
  144. 'filter' => $filter,
  145. 'filter_form' => $filter->getField()->createView()
  146. )));
  147. }
  148. /**
  149. * render a view element
  150. *
  151. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  152. * @param mixed $object
  153. * @return string
  154. */
  155. public function renderViewElement(FieldDescriptionInterface $fieldDescription, $object)
  156. {
  157. $template = $this->getTemplate($fieldDescription, 'SonataAdminBundle:CRUD:base_view_field.html.twig');
  158. try {
  159. $value = $fieldDescription->getValue($object);
  160. } catch (NoValueException $e) {
  161. $value = null;
  162. }
  163. return $this->output($fieldDescription, $template, array(
  164. 'field_description' => $fieldDescription,
  165. 'object' => $object,
  166. 'value' => $value
  167. ));
  168. }
  169. /**
  170. * render a field element from the FieldDescription
  171. *
  172. * @throws InvalidArgumentException
  173. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  174. * @param \Sumfony\Component\Form\FormView $formView
  175. * @param mixed $object
  176. * @param array $params
  177. * @return string
  178. */
  179. public function renderFormElement(FieldDescriptionInterface $fieldDescription, FormView $formView, $object, $params = array())
  180. {
  181. if (!$fieldDescription->getFieldName()) {
  182. return '';
  183. }
  184. if (!$formView->offsetExists($fieldDescription->getFieldName())) {
  185. return;
  186. }
  187. $children = $formView->offsetGet($fieldDescription->getFieldName());
  188. if (in_array('hidden', $children->get('types'))) {
  189. return '';
  190. }
  191. // find the correct edit parameter
  192. // edit : standard | inline
  193. // inline : natural | table
  194. $parentFieldDescription = $fieldDescription->getAdmin()->getParentFieldDescription();
  195. if (!$parentFieldDescription) {
  196. $params['edit'] = $fieldDescription->getOption('edit', 'standard');
  197. $params['inline'] = $fieldDescription->getOption('inline', 'natural');
  198. $base_template = sprintf('SonataAdminBundle:CRUD:base_%s_edit_field.html.twig', 'standard');
  199. } else {
  200. $params['edit'] = $parentFieldDescription->getOption('edit', 'standard');
  201. $params['inline'] = $parentFieldDescription->getOption('inline', 'natural');
  202. $base_template = sprintf('SonataAdminBundle:CRUD:base_%s_edit_field.html.twig', $params['edit']);
  203. }
  204. $template = $this->getTemplate($fieldDescription, 'SonataAdminBundle:CRUD:base_standard_edit_field.html.twig');
  205. return $this->output($fieldDescription, $template, array_merge($params, array(
  206. 'admin' => $fieldDescription->getAdmin(),
  207. 'object' => $object,
  208. 'field_description' => $fieldDescription,
  209. 'value' => $this->getValueFromFieldDescription($object, $fieldDescription, $params),
  210. 'field_element' => $children,
  211. 'base_template' => $fieldDescription->getOption('base_template', $base_template)
  212. )));
  213. }
  214. /**
  215. * @throws \RunTimeException
  216. * @param $element
  217. * @param \Sonata\AdminBundle\Admin\FieldDescriptionInterface $fieldDescription
  218. * @return mixed
  219. */
  220. public function renderRelationElement($element, FieldDescriptionInterface $fieldDescription)
  221. {
  222. $method = $fieldDescription->getOption('associated_tostring', '__toString');
  223. if (!method_exists($element, $method)) {
  224. throw new \RunTimeException(sprintf('You must define an `associated_tostring` option or create a `%s::__toString` method to the field option %s from service %s is ', get_class($element), $fieldDescription->getName(), $fieldDescription->getAdmin()->getCode()));
  225. }
  226. return call_user_func(array($element, $method));
  227. }
  228. }