diff --git a/Controller/AdminController.php b/Controller/AdminController.php index e80ea9950f..27e0c3aba3 100644 --- a/Controller/AdminController.php +++ b/Controller/AdminController.php @@ -421,8 +421,40 @@ protected function findBy($entityClass, $searchQuery, array $searchableFields, $ */ protected function createEditForm($entity, array $entityProperties) { + return $this->createEntityForm($entity, $entityProperties, 'edit'); + } + + /** + * Creates the form used to create an entity. + * + * @param object $entity + * @param array $entityProperties + * + * @return Form + */ + protected function createNewForm($entity, array $entityProperties) + { + return $this->createEntityForm($entity, $entityProperties, 'new'); + } + + /** + * Creates the form used to create or edit an entity. + * + * @param object $entity + * @param array $entityProperties + * @param string $view The name of the view where this form is used ('new' or 'edit') + * + * @return Form + */ + protected function createEntityForm($entity, array $entityProperties, $view) + { + $formCssClass = array_reduce($this->config['design']['form_theme'], function($previousClass, $formTheme) { + return sprintf('theme_%s %s', strtolower(str_replace('.html.twig', '', basename($formTheme))), $previousClass); + }); + $form = $this->createFormBuilder($entity, array( 'data_class' => $this->entity['class'], + 'attr' => array('class' => $formCssClass, 'id' => $view.'-form'), )); foreach ($entityProperties as $name => $metadata) { @@ -440,25 +472,16 @@ protected function createEditForm($entity, array $entityProperties) } } + $formFieldOptions['attr']['field_type'] = $metadata['fieldType']; + $formFieldOptions['attr']['field_css_class'] = $metadata['class']; + $formFieldOptions['attr']['field_help'] = $metadata['help']; + $form->add($name, $metadata['fieldType'], $formFieldOptions); } return $form->getForm(); } - /** - * Creates the form used to create an entity. - * - * @param object $entity - * @param array $entityProperties - * - * @return Form - */ - protected function createNewForm($entity, array $entityProperties) - { - return $this->createEditForm($entity, $entityProperties); - } - /** * It returns the name of the first entity configured in the backend. It's * mainly used to redirect the homepage of the backend to the listing of the diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 39778a684d..03cf9ecce4 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -203,11 +203,28 @@ private function addDesignSection(ArrayNodeDefinition $rootNode) ->defaultValue('default') ->info('The theme used to render the backend pages. For now this value can only be "default".') ->validate() - ->ifNotInArray(array('default')) + ->ifNotInArray(array('default')) ->thenInvalid('The theme name can only be "default".') ->end() ->end() + ->variableNode('form_theme') + ->defaultValue(array('@EasyAdmin/form/bootstrap_3_horizontal_layout.html.twig')) + ->treatNullLike(array('@EasyAdmin/form/bootstrap_3_horizontal_layout.html.twig')) + ->info('The form theme applied to backend forms. Allowed values: "horizontal", "vertical" and a custom theme path or array of custom theme paths.') + ->validate() + ->ifTrue(function ($v) { return 'horizontal' === $v; }) + ->then(function () { return array('@EasyAdmin/form/bootstrap_3_horizontal_layout.html.twig'); }) + ->end() + ->validate() + ->ifTrue(function ($v) { return 'vertical' === $v; }) + ->then(function () { return array('@EasyAdmin/form/bootstrap_3_layout.html.twig'); }) + ->end() + ->validate() + ->ifString()->then(function($v) { return array($v); }) + ->end() + ->end() + ->arrayNode('assets') ->performNoDeepMerging() ->addDefaultsIfNotSet() diff --git a/Resources/doc/10-customizing-design.md b/Resources/doc/10-customizing-design.md index e9ef543482..4c2dde2bc7 100644 --- a/Resources/doc/10-customizing-design.md +++ b/Resources/doc/10-customizing-design.md @@ -26,6 +26,90 @@ easy_admin: # ... ``` +Customizing Form Design +----------------------- + +By default, forms are displayed using the **horizontal style** defined by the +Bootstrap 3 CSS framework: + +![Default horizontal form style](images/easyadmin-form-horizontal.png) + +The style of the forms can be changed application-wide using the `form_theme` +option inside the `design` configuration section. In fact, the default form +style is equivalent to using this configuration: + +```yaml +easy_admin: + design: + form_theme: 'horizontal' + # ... +``` + +If you prefer to display your forms using the **vertical style** defined by +Bootstrap, change the value of this option to `vertical`: + +```yaml +easy_admin: + design: + form_theme: 'vertical' + # ... +``` + +The same form shown previously will now be rendered as follows: + +![Vertical form style](images/easyadmin-form-vertical.png) + +The `horizontal` and `vertical` values are just nice shortcuts to use any of +the two built-in form themes. But you can also use your own form themes. Just +set the full theme path as the value of the `form_theme` option: + +```yaml +easy_admin: + design: + form_theme: '@AppBundle/form/custom_layout.html.twig' + # ... +``` + +You can even pass several form themes paths in an array to use all of them when +rendering the backend forms: + +```yaml +easy_admin: + design: + form_theme: + - '@AppBundle/form/custom_layout.html.twig' + - 'form_div_layout.html.twig' + # ... +``` + +### Multiple-Column Forms + +EasyAdmin doesn't provide any mechanism to create multi-column form layouts. +However, you can use the `class` form field to create these advanced layouts. +The `class` value is applied to the parent `
` element which contains the +field label, the field widget, the field help and the optional field errors: + +![Multi-column form](images/easyadmin-form-multi-column.png) + +The configuration used to display this form is the following: + + ```yaml +easy_admin: + design: + form_theme: 'vertical' + entities: + Product: + # ... + form: + fields: + - { property: name, class: 'col-sm-12' } + - { property: price, type: 'number', help: 'Prices are always in euros', class: 'col-sm-6' } + - { property: 'ean', label: 'EAN', help: 'EAN 13 valid code. Leave empty if unknown.', class: 'col-sm-6' } + - { property: 'enabled', class: 'col-sm-12' } + - { property: 'description', class: 'col-sm-12' } + # ... +``` + Adding Custom Web Assets ------------------------ diff --git a/Resources/doc/6-customizing-new-edit-views.md b/Resources/doc/6-customizing-new-edit-views.md index 962b816a7b..3008dee226 100644 --- a/Resources/doc/6-customizing-new-edit-views.md +++ b/Resources/doc/6-customizing-new-edit-views.md @@ -177,8 +177,10 @@ These are the options that you can define for form fields: * `help` (optional): the help message that will be displayed below the form field. * `class` (optional): the CSS class that will be applied to the form field - widget. For example, to display a big input field, use the Bootstrap 3 - class called `input-lg`. + widget container element. For example, when using the default Bootstrap + based form theme, this value is applied to the `
` + element which wraps the label, the widget and the error messages of the + field. ### Translate Form Field Labels diff --git a/Resources/doc/images/easyadmin-form-horizontal.png b/Resources/doc/images/easyadmin-form-horizontal.png new file mode 100644 index 0000000000..261f98982b Binary files /dev/null and b/Resources/doc/images/easyadmin-form-horizontal.png differ diff --git a/Resources/doc/images/easyadmin-form-multi-column.png b/Resources/doc/images/easyadmin-form-multi-column.png new file mode 100644 index 0000000000..07f0bac297 Binary files /dev/null and b/Resources/doc/images/easyadmin-form-multi-column.png differ diff --git a/Resources/doc/images/easyadmin-form-vertical.png b/Resources/doc/images/easyadmin-form-vertical.png new file mode 100644 index 0000000000..43868f773f Binary files /dev/null and b/Resources/doc/images/easyadmin-form-vertical.png differ diff --git a/Resources/public/stylesheet/admin.css b/Resources/public/stylesheet/admin.css index fa4f432775..b9349d4f23 100644 --- a/Resources/public/stylesheet/admin.css +++ b/Resources/public/stylesheet/admin.css @@ -706,6 +706,20 @@ body.new form textarea { body.new form .form-inline select + select { margin-left: .5em; } +body.new form .field_collection_action { + margin-top: -15px; +} + +body.new form.theme_bootstrap_3_horizontal_layout #form-actions-row { + padding-left: 15px; + padding-right: 15px; +} + +@media (min-width: 768px) { + body.new form.theme_bootstrap_3_horizontal_layout #form-actions-row { + margin-left: 16.66666667%; + } +} /* ------------------------------------------------------------------------- EDIT PAGE @@ -716,6 +730,20 @@ body.edit form textarea { body.edit form .form-inline select + select { margin-left: .5em; } +body.edit form .field_collection_action { + margin-top: -15px; +} + +body.edit form.theme_bootstrap_3_horizontal_layout #form-actions-row { + padding-left: 15px; + padding-right: 15px; +} + +@media (min-width: 768px) { + body.edit form.theme_bootstrap_3_horizontal_layout #form-actions-row { + margin-left: 16.66666667%; + } +} /* ------------------------------------------------------------------------- SHOW PAGE diff --git a/Resources/views/edit.html.twig b/Resources/views/edit.html.twig index ddc4cfa501..f60bd71db1 100644 --- a/Resources/views/edit.html.twig +++ b/Resources/views/edit.html.twig @@ -5,7 +5,7 @@ {% trans_default_domain "EasyAdminBundle" %} {% set _trans_parameters = { '%entity_name%': _entity.label|trans, '%entity_id%': attribute(item, _entity.primary_key_field_name) } %} -{% form_theme form '@EasyAdmin/form/bootstrap_3_horizontal_layout.html.twig' %} +{% form_theme form with easyadmin_config('design.form_theme') %} {% block body_class 'admin edit ' ~ _entity.name|lower %} @@ -14,98 +14,10 @@ {% endblock %} {% block main %} - {{ form_start(form, { attr: { id: 'edit-form', novalidate: 'novalidate' } }) }} -
- {% for field in form.children if field.vars.name != '_token' %} - {% set _field_metadata = entity_fields[field.vars.name] %} -
- {% if _field_metadata['fieldType'] == 'association' %} - {{ easyadmin_render_field_for_edit_view(item, _field_metadata) }} - {% else %} - {% set field_label = _field_metadata['label']|default(null) %} - {{ form_label(field, field_label|trans(_trans_parameters), { label_attr: { class: 'col-sm-2 control-label' } }) }} - -
- {% set widget_attributes = { attr: { class: _field_metadata['class']|default(null) }, label: _field_metadata['label']|trans } %} - {{ form_widget(field, widget_attributes) }} - {{ form_errors(field) }} - - {% if _field_metadata['help'] is defined %} - {{ _field_metadata['help'] }} - {% endif %} - - {% if _field_metadata['fieldType'] == 'collection' %} - {% set add_item_javascript %} - $(function() { - if(event.preventDefault) event.preventDefault(); else event.returnValue = false; - - var collection = $('#form_{{ field.vars.name|escape('js') }}'); - var numItems = collection.children('div.form-group').length; - - var newItem = collection.attr('data-prototype') - .replace(/__name__label__/g, numItems) - .replace(/__name__/g, numItems) - ; - - collection.append(newItem); - }); - {% endset %} - - - {{ field|length == 0 ? 'Add a new item' : 'Add another item' }} - - - {% endif %} -
- {% endif %} -
- {% endfor %} - -
-
- {# the 'save' action is hardcoded for the 'edit' view #} - - - {% set _edit_actions = easyadmin_get_actions_for_edit_item(_entity.name) %} - {% for _action in _edit_actions %} - {% if 'method' == _action.type %} - {% set _action_href = path('admin', { action: _action.name, view: 'edit', entity: _entity.name, id: attribute(item, _entity.primary_key_field_name) }) %} - {% elseif 'route' == _action.type %} - {% set _action_href = path(_action.name, { entity: _entity.name, id: attribute(item, _entity.primary_key_field_name) }) %} - {% endif %} - - - {% if _action.icon %}{% endif %} - {{ _action.label|trans(_trans_parameters) }} - - {% endfor %} - - {% if easyadmin_action_is_enabled_for_edit_view('delete', _entity.name) %} - {% set _action = easyadmin_get_action_for_edit_view('delete', _entity.name) %} - - {% endif %} - - {# for aesthetic reasons, the 'list' action is always displayed as a link instead of a button #} - {% if easyadmin_action_is_enabled_for_edit_view('list', _entity.name) %} - {% set _action = easyadmin_get_action_for_edit_view('list', _entity.name) %} - {% spaceless %} - {% if _action.icon %}{% endif %} - {{ _action.label|default('action.list')|trans(_trans_parameters) }} - {% endspaceless %} - {% endif %} -
-
-
- {{ form_end(form) }} + {{ include('@EasyAdmin/form/entity_form.html.twig', { view: 'edit' }) }} {{ form(delete_form, { attr: { id: 'delete-form', style: 'display: none' }}) }} -