the_form_view.rst 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. The Form View
  2. =============
  3. You've seen the absolute top of the iceberg in
  4. :doc:`the previous chapter <creating_an_admin>`. But there is a lot more to
  5. discover! In the coming chapters, you'll create an Admin class for the more
  6. complex ``BlogPost`` model. Meanwhile, you'll learn how to make things a bit
  7. more pretty.
  8. Bootstrapping the Admin Class
  9. -----------------------------
  10. The basic class definition will look the same as the ``CategoryAdmin``:
  11. .. code-block:: php
  12. // src/AppBundle/Admin/BlogPostAdmin.php
  13. namespace AppBundle\Admin;
  14. use Sonata\AdminBundle\Admin\AbstractAdmin;
  15. use Sonata\AdminBundle\Datagrid\ListMapper;
  16. use Sonata\AdminBundle\Form\FormMapper;
  17. class BlogPostAdmin extends AbstractAdmin
  18. {
  19. protected function configureFormFields(FormMapper $formMapper)
  20. {
  21. // ... configure $formMapper
  22. }
  23. protected function configureListFields(ListMapper $listMapper)
  24. {
  25. // ... configure $listMapper
  26. }
  27. }
  28. The same applies to the service definition:
  29. .. code-block:: yaml
  30. # app/config/services.yml
  31. services:
  32. # ...
  33. admin.blog_post:
  34. class: AppBundle\Admin\BlogPostAdmin
  35. arguments: [~, AppBundle\Entity\BlogPost, ~]
  36. tags:
  37. - { name: sonata.admin, manager_type: orm, label: Blog post }
  38. public: true
  39. Configuring the Form Mapper
  40. ---------------------------
  41. If you already know the `Symfony Form component`_, the ``FormMapper`` will look
  42. very similar.
  43. You use the ``add()`` method to add fields to the form. The first argument is
  44. the name of the property the field value maps to, the second argument is the
  45. type of the field (see the `field type reference`_) and the third argument are
  46. additional options to customize the form type. Only the first argument is
  47. required as the Form component has type guessers to guess the type.
  48. The ``BlogPost`` model has 4 properties: ``id``, ``title``, ``body``,
  49. ``category``. The ``id`` property's value is generated automatically by the
  50. database. This means the form view just needs 3 fields: title, body and
  51. category.
  52. The title and body fields are simple "text" and "textarea" fields, you can add
  53. them straight away:
  54. .. code-block:: php
  55. // src/AppBundle/Admin/BlogPostAdmin.php
  56. // ...
  57. protected function configureFormFields(FormMapper $formMapper)
  58. {
  59. $formMapper
  60. ->add('title', 'text')
  61. ->add('body', 'textarea')
  62. ;
  63. }
  64. However, the category field will reference another model. How can you solve that?
  65. Adding Fields that Reference Other Models
  66. -----------------------------------------
  67. You have a couple different choices on how to add fields that reference other
  68. models. The most basic choice is to use the `entity field type`_ provided by
  69. the DoctrineBundle. This will render a choice field with the available entities
  70. as choice.
  71. .. code-block:: php
  72. // src/AppBundle/Admin/BlogPostAdmin.php
  73. // ...
  74. protected function configureFormFields(FormMapper $formMapper)
  75. {
  76. $formMapper
  77. // ...
  78. ->add('category', 'entity', array(
  79. 'class' => 'AppBundle\Entity\Category',
  80. 'property' => 'name',
  81. ))
  82. ;
  83. }
  84. .. note::
  85. The `property`_ option is not supported by Symfony >= 2.7. You should use `choice_label`_ instead.
  86. As each blog post will only have one category, it renders as a select list:
  87. .. image:: ../images/getting_started_entity_type.png
  88. When an admin would like to create a new category, they need to go to the
  89. category admin page and create a new category.
  90. Using the Sonata Model Type
  91. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  92. To make life easier for admins, you can use the
  93. :ref:`sonata_type_model field type <field-types-model>`. This field type will
  94. also render as a choice field, but it includes a create button to open a
  95. dialog with the admin of the referenced model in it:
  96. .. code-block:: php
  97. // src/AppBundle/Admin/BlogPostAdmin.php
  98. // ...
  99. protected function configureFormFields(FormMapper $formMapper)
  100. {
  101. $formMapper
  102. // ...
  103. ->add('category', 'sonata_type_model', array(
  104. 'class' => 'AppBundle\Entity\Category',
  105. 'property' => 'name',
  106. ))
  107. ;
  108. }
  109. .. image:: ../images/getting_started_sonata_model_type.png
  110. Using Groups
  111. ------------
  112. Currently, everything is put into one block. Since the form only has three
  113. fields, it is still usable, but it can become quite a mess pretty quick. To
  114. solve this, the form mapper also supports grouping fields together.
  115. For instance, the title and body fields can belong to the Content group and the
  116. category field to a Meta data group. To do this, use the ``with()`` method:
  117. .. code-block:: php
  118. // src/AppBundle/Admin/BlogPostAdmin.php
  119. // ...
  120. protected function configureFormFields(FormMapper $formMapper)
  121. {
  122. $formMapper
  123. ->with('Content')
  124. ->add('title', 'text')
  125. ->add('body', 'textarea')
  126. ->end()
  127. ->with('Meta data')
  128. ->add('category', 'sonata_type_model', array(
  129. 'class' => 'AppBundle\Entity\Category',
  130. 'property' => 'name',
  131. ))
  132. ->end()
  133. ;
  134. }
  135. The first argument is the name/label of the group and the second argument is an
  136. array of options. For instance, you can pass HTML classes to the group in
  137. order to tweak the styling:
  138. .. code-block:: php
  139. // src/AppBundle/Admin/BlogPostAdmin.php
  140. // ...
  141. protected function configureFormFields(FormMapper $formMapper)
  142. {
  143. $formMapper
  144. ->with('Content', array('class' => 'col-md-9'))
  145. // ...
  146. ->end()
  147. ->with('Meta data', array('class' => 'col-md-3')
  148. // ...
  149. ->end()
  150. ;
  151. }
  152. This will now result in a much nicer edit page:
  153. .. image:: ../images/getting_started_post_edit_grid.png
  154. Using Tabs
  155. ~~~~~~~~~~
  156. If you get even more options, you can also use multiple tabs by using the
  157. ``tab()`` shortcut method:
  158. .. code-block:: php
  159. $formMapper
  160. ->tab('Post')
  161. ->with('Content', ...)
  162. // ...
  163. ->end()
  164. // ...
  165. ->end()
  166. ->tab('Publish Options')
  167. // ...
  168. ->end()
  169. ;
  170. Creating a Blog Post
  171. --------------------
  172. You've now finished your nice form view for the ``BlogPost`` model. Now it's
  173. time to test it out by creating a post.
  174. After pressing the "Create" button, you probably see a green message like:
  175. *Item "AppBundle\Entity\BlogPost:00000000192ba93c000000001b786396" has been
  176. successfully created.*
  177. While it's very friendly of the SonataAdminBundle to notify the admin of a
  178. successful creation, the classname and some sort of hash aren't really nice to
  179. read. This is the default string representation of an object in the
  180. SonataAdminBundle. You can change it by defining a ``toString()`` method in the
  181. Admin class. This receives the object to transform to a string as the first parameter:
  182. .. note::
  183. No underscore prefix! ``toString()`` is correct!
  184. .. code-block:: php
  185. // src/AppBundle/Admin/BlogPostAdmin.php
  186. // ...
  187. use AppBundle\Entity\BlogPost;
  188. class BlogPostAdmin extends AbstractAdmin
  189. {
  190. // ...
  191. public function toString($object)
  192. {
  193. return $object instanceof BlogPost
  194. ? $object->getTitle()
  195. : 'Blog Post'; // shown in the breadcrumb on the create view
  196. }
  197. }
  198. Round Up
  199. --------
  200. In this tutorial, you've made your first contact with the greatest feature of
  201. the SonataAdminBundle: Being able to customize literally everything. You've
  202. started by creating a simple form and ended up with a nice edit page for your
  203. admin.
  204. In the :doc:`next chapter <the_list_view>`, you're going to look at the list
  205. and datagrid actions.
  206. .. _`Symfony Form component`: http://symfony.com/doc/current/book/forms.html
  207. .. _`field type reference`: http://symfony.com/doc/current/reference/forms/types.html
  208. .. _`entity field type`: http://symfony.com/doc/current/reference/forms/types/entity.html
  209. .. _`choice_label`: http://symfony.com/doc/current/reference/forms/types/entity.html#choice-label
  210. .. _`property`: http://symfony.com/doc/2.6/reference/forms/types/entity.html#property