Podaje kod z templatki od edycji formualrza:
MlBackendBundle:Products:edit.html.twig
{% extends '::backendlayout.html.twig' %}
{% set imgPath = app_config.products_path %}
{% set noImg = app_config.product_no_photo %}
{% block title %}Edytuj produkt | {{ parent() }}{% endblock %}
{% block breadcrumbs -%}
<li><a href="{{ path('backend') }}"><i class="fa fa-dashboard"></i> Strona startowa
</a></li> <li><a href="{{ path('backend_products') }}">Lista produktów
</a></li> <li class="active">Edytuj produkt
</li> {% endblock breadcrumbs -%}
{% block backendcontent -%}
{% include "MlBackendBundle:Products:top_menu.html.twig" %}
<h1><span class="glyphicon glyphicon-briefcase"></span> Edytuj produkt
</h1>
<form id="jsForm" action="{{ path('backend_products_update', { 'id': entity.id }) }}" class="form-horizontal col-md-12" method="POST" {{form_enctype(form)}}> <input id="saveClose" type="hidden" name="saveClose" value="no"> <div class="col-md-offset-3 col-md-9"> <button type="submit" name="subvalider" class="btn btn-primary"><span class="glyphicon glyphicon-save"></span> Zapisz
</button> <a href="#" class="btn btn-primary submit-btn"><span class="glyphicon glyphicon-ok"></span> Zapisz i zamknij
</a> <a href="#" id="delete-btn" class="btn btn-danger" data-toggle="modal" data-target="#deleteModal" data-entity-id="{{ entity.id }}"><span class="glyphicon glyphicon-trash"></span> Usuń
</a> <a href="{{ path('backend_products') }}" class="btn btn-success"><span class="glyphicon glyphicon-share-alt"></span> Powrót
</a>
{% include "MlBackendBundle:Products:form.html.twig" %}
<div class="col-md-offset-3 col-md-9"> <button type="submit" name="subvalider" class="btn btn-primary"><span class="glyphicon glyphicon-save"></span> Zapisz
</button> <a href="#" class="btn btn-primary submit-btn"><span class="glyphicon glyphicon-ok"></span> Zapisz i zamknij
</a> <a href="#" id="delete-btn" class="btn btn-danger" data-toggle="modal" data-target="#deleteModal" data-entity-id="{{ entity.id }}"><span class="glyphicon glyphicon-trash"></span> Usuń
</a> <a href="{{ path('backend_products') }}" class="btn btn-success"><span class="glyphicon glyphicon-share-alt"></span> Powrót
</a>
{% include "MlBackendBundle:Default:delete_modal.html.twig" %}
<form id="deleteForm" action="{{ path('backend_products_delete', { 'id': entity.id }) }}" method="POST"> {{ form_widget(delete_form) }}
{% endblock backendcontent -%}
{% block javascripts %}
{{ parent() }}
(function($) {
$('#delete-btn').on('click', function () {
$('.remove_item').attr('data-entity-id', entityId);
});
$('.submit-btn').on('click', function () {
$('#saveClose').val("yes");
$('#jsForm').submit();
return false;
});
$(".remove_item").click(function () {
$('#deleteForm').submit();
return false;
});
var forms = $('#jsForm'),
vat = forms.find('#ml_backendbundle_products_vatValue'),
netto = forms.find('#ml_backendbundle_products_priceNetto'),
brutto = forms.find('#ml_backendbundle_products_priceBrutto');
netto.change(function() {
var nettoTmp = parseFloat(netto.val());
var vatTmp = parseFloat(vat.val());
if(nettoTmp >= 0 ){
priceBrutto = nettoTmp + (nettoTmp * vatTmp);
brutto.val(priceBrutto.toFixed(2));
}
});
brutto.change(function() {
var bruttoTmp = parseFloat(brutto.val());
var vatTmp = parseFloat(vat.val());
if(bruttoTmp >= 0 ){
var priceNetto = bruttoTmp / ((vatTmp*100 + 100)/100);
netto.val(priceNetto.toFixed(2));
}
});
// Images
var imageCount = '{{ form.images|length }}';
$('#add-another-image').click(function(e) {
e.preventDefault();
var imageList = $('#image-fields-list');
// grab the prototype template
var newWidget = imageList.attr('data-prototype');
// replace the "__name__" used in the id and name of the prototype
// with a number that's unique to your images
newWidget = newWidget.replace(/__ml_backendbundle_products[images][0][file]__/g, imageCount);
imageCount++;
// create a new list element and add it to the list
var newLi = $('
<li></li>').html(newWidget);
newLi.appendTo(imageList);
});
// Documents
var documentCount = '{{ form.documents|length }}';
$('#add-another-document').click(function(e) {
e.preventDefault();
var documentList = $('#document-fields-list');
var newWidget = documentList.attr('data-prototype');
newWidget = newWidget.replace(/__ml_backendbundle_products[documents][0][file]__/g, documentCount);
documentCount++;
var newLi = $('
<li></li>').html(newWidget);
newLi.appendTo(documentList);
});
// Attributes
var attributeCount = '{{ form.attributes|length }}';
$('#add-another-attribute').click(function(e) {
e.preventDefault();
var attributeList = $('#attribute-fields-list');
var newWidget = attributeList.attr('data-prototype');
newWidget = newWidget.replace(/__ml_backendbundle_products[attributes][0][file]__/g, attributeCount);
attributeCount++;
var newLi = $('
<li></li>').html(newWidget);
newLi.appendTo(attributeList);
});
/* Fancybox */
$(".fancybox").fancybox({
helpers: {
title : {
type : 'inside'
}
},
beforeShow : function() {
var title = this.element.find('img').attr('title');
this.inner.find('img').attr('title', title);
this.title = title;
}
});
})(jQuery);
{% endblock %}
Kod formularza:
{% set imgPath = app_config.products_path %}
{% set noImg = app_config.product_no_photo %}
{% set docPath = app_config.products_doc_path %}
{% set noDoc = app_config.product_no_doc %}
<ul class="nav nav-tabs"> <li class="active"><a href="#tab1" data-toggle="tab"><span class="glyphicon glyphicon-cog"></span> Konfiguracja podstawowa
</a></li> <li><a href="#tab2" data-toggle="tab"><span class="glyphicon glyphicon-picture"></span> Galeria zdjęć
</a></li> <li><a href="#tab3" data-toggle="tab"><span class="glyphicon glyphicon-folder-open"></span> Dokumenty
</a></li> <li><a href="#tab4" data-toggle="tab"><span class="glyphicon glyphicon-list-alt"></span> Atrybuty
</a></li> <li><a href="#tab5" data-toggle="tab"><span class="glyphicon glyphicon-globe"></span> Pozycjonowanie
</a></li> <div class="tab-content"> <div class="tab-pane active" id="tab1"> {{ form_row(form.sku, { 'label' : 'SKU (nr katalogowy)' }) }}
{{ form_row(form.name, { 'label' : 'Nazwa' }) }}
{{ form_row(form.slug, { 'label' : 'Przyjazny link' }) }}
<label for="" class="col-sm-2 control-label"> </label> <span class="help-block"> <ul class="list-unstyled"> <span class="glyphicon glyphicon-info-sign"></span> Przyjazny link zostanie wykorzystany w adresach URL. Pozostaw to miejsce puste, a system wypełni je wartością domyślną na podstawie nazwy.
{{ form_row(form.shortDescription, { 'label' : 'Skrócony opis' }) }}
<label for="" class="col-sm-2 control-label"> </label> <span class="help-block"> <ul class="list-unstyled"> <span class="glyphicon glyphicon-info-sign"></span> Maksymalnie 255 znaków.
{{ form_row(form.description, { 'label' : 'Pełny opis' }) }}
{{ form_row(form.vatValue, { 'label' : 'Stawka VAT', 'attr' : { 'class' : 'js-vat' } }) }}
{{ form_row(form.priceNetto, { 'label' : 'Cena netto' }) }}
{{ form_row(form.priceBrutto, { 'label' : 'Cena brutto' }) }}
{{ form_row(form.oldPriceNetto, { 'label' : 'Stara cena netto', 'attr' : { 'class' : 'js-netto' }}) }}
{{ form_row(form.oldPriceBrutto, { 'label' : 'Stara cena brutto', 'attr' : { 'class' : 'js-brutto' } }) }}
{{ form_row(form.hidePrice, { 'label' : 'Cena ukryta' }) }}
{{ form_row(form.isNew, { 'label' : 'Nowość' }) }}
{{ form_row(form.isPromo, { 'label' : 'Promocja' }) }}
{{ form_row(form.isPopular, { 'label' : 'Popularny produkt' }) }}
{{ form_row(form.availability, { 'label' : 'Dostępność' }) }}
{{ form_row(form.isActive, { 'label' : 'Stan publikacji' }) }}
{{ form_row(form.created, { 'label' : 'Data utworzenia' }) }}
{{ form_row(form.updated, { 'label' : 'Data modyfikacji' }) }}
{{ form_row(form.views, { 'label' : 'Odsłony' }) }}
{{ form_row(form.brands, { 'label' : 'Producent' }) }}
{{ form_row(form.getCategories, { 'label' : 'Kategoria' }) }}
<div class="tab-pane" id="tab2"> <ul id="image-fields-list" data-prototype="{{ form_widget(form.images.vars.prototype)|e }}"> {% for imageField in form.images %}
<label for="" class="col-sm-2 control-label">Plik graficzny
</label> {# imageField: {{ dump(imageField) }} #}
{# img class="myavatar" #}
{% if imageField.vars.data.filename %}
<a class="fancybox" href="{{ asset(imgPath) }}{{ imageField.vars.data.products.slug }}/{{ imageField.vars.data.filename }}"> <img class="img-responsive thumbnail" src="{{ asset(imgPath) }}{{ imageField.vars.data.products.slug }}/{{ imageField.vars.data.filename }}" width="100" height="100" title="{{ imageField.vars.data.title }}" alt="{{ imageField.vars.data.alt }}" /></a> {% elseif imageField.vars.data.filename is empty %}
<img src="{{ asset(imgPath) }}{{ noImg }}" title="{{ imageField.vars.data.title }}" alt="{{ imageField.vars.data.alt }}" />{% endif %}
{{ form_errors(imageField) }}
{{ form_widget(imageField) }}
<div class="clearfix list-splitter" style="margin: 30px 0"></div> {% endfor %}
<ul class="hidden-print"> <a href="#" id="add-another-image"> <span class="glyphicon glyphicon-plus"></span> Dodaj zdjęcie
<div class="tab-pane" id="tab3"> {# {{ form_row(form.documents, { 'label' : ' ' }) }} #}
<ul id="document-fields-list" data-prototype="{{ form_widget(form.documents.vars.prototype)|e }}"> {% for documentField in form.documents %}
<label for="" class="col-sm-2 control-label">Plik z dokumentem
</label> {# documentField: {{ dump(documentField) }} #}
{% if documentField.vars.data.filename %}
<a href="{{ asset(docPath) }}{{ documentField.vars.data.products.slug }}/{{ documentField.vars.data.filename }}" target="_blank" data-toggle="tooltip" data-placement="top" title="Pobierz dokument" /> {{ documentField.vars.data.filename }}
</a> {% elseif documentField.vars.data.filename %}
<img src="{{ asset(docPath) }}{{ noDoc }}" title="{{ documentField.vars.data.title }}" alt="{{ documentField.vars.data.title }}" />{% endif %}
{{ form_errors(documentField) }}
{{ form_widget(documentField) }}
<div class="clearfix list-splitter" style="margin: 30px 0"></div> {% endfor %}
<ul class="hidden-print"> <a href="#" id="add-another-document"> <span class="glyphicon glyphicon-plus"></span> Dodaj dokument
<div class="tab-pane" id="tab4"> {# {{ form_row(form.attributes, { 'label' : ' ' }) }} #}
<ul id="attribute-fields-list" data-prototype="{{ form_widget(form.attributes.vars.prototype)|e }}"> {% for attributeField in form.attributes %}
{{ form_errors(attributeField) }}
{{ form_widget(attributeField) }}
<div class="clearfix list-splitter" style="margin: 30px 0"></div> {% endfor %}
<ul class="hidden-print"> <a href="#" id="add-another-attribute"> <span class="glyphicon glyphicon-plus"></span> Dodaj atrybut
<div class="tab-pane" id="tab5"> {{ form_row(form.metaTitle, { 'label' : 'Znacznik meta - tytuł' }) }}
{{ form_row(form.metaKeywords, { 'label' : 'Znacznik meta - słowa kluczowe' }) }}
{{ form_row(form.metaDescription, { 'label' : 'Znacznik meta - opis' }) }}
{{ form_rest(form) }}
Kod
Formularze zostaly wygenerowane automatycznie - panele CRUD. Pozniej poddalem je modyfikacji.
Fragment z kontrolera:
[php]
/**
* Displays a form to edit an existing Products entity.
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('MlBackendBundle:Products')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Products entity.');
}
$editForm = $this->createForm(new ProductsType(), $entity);
$deleteForm = $this->createDeleteForm($id);
return $this->render('MlBackendBundle:Products:edit.html.twig', array(
'entity' => $entity,
'form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
[/php]
fragment ProductsType:
[php]
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('sku', 'text', array('label' => 'SKU (nr katalogowy)'))
->add('name', 'text', array('label' => 'Nazwa'))
->add('slug', 'text', array('label' => 'Przyjazny link', 'required' => false))
->add('vatValue', 'choice', array('label' => 'Stawka VAT', 'choices' => array('0.23' => '23%', '0.08' => '8%')))
->add('priceNetto', 'text', array('label' => 'Cena netto'))
->add('priceBrutto', 'text', array('label' => 'Cena brutto'))
->add('oldPriceNetto', 'text', array('label' => 'Stara cena netto', 'required' => true, 'data' => '0.00'))
->add('oldPriceBrutto', 'text', array('label' => 'Stara cena brutto', 'required' => true, 'data' => '0.00'))
->add('hidePrice', 'choice', array('label' => 'Cena ukryta', 'choices' => array('0' => 'Nie', '1' => 'Tak'), 'required' => true))
->add('isActive', 'choice', array('label' => 'Stan publikacji', 'choices' => array('1' => 'Opublikowano', '0' => 'Nie opublikowano'), 'required' => true))
->add('isNew', 'choice', array('label' => 'Nowość', 'choices' => array('0' => 'Nie', '1' => 'Tak'), 'required' => true))
->add('isPromo', 'choice', array('label' => 'Promocja', 'choices' => array('0' => 'Nie', '1' => 'Tak'), 'required' => true))
->add('isPopular', 'choice', array('label' => 'Popularny produkt', 'choices' => array('0' => 'Nie', '1' => 'Tak'), 'required' => true))
->add('created', 'datetime', array('widget' => 'single_text', 'format' => 'dd-MM-yyyy hh:mm:ss', 'attr' => array('class' => 'datetimepicker')))
->add('updated', 'datetime', array('widget' => 'single_text', 'format' => 'dd-MM-yyyy hh:mm:ss', 'attr' => array('class' => 'datetimepicker')))
->add('views', 'integer', array('label' => 'Ilość odsłon', 'required' => false, 'data' => '0'))
->add('shortDescription', 'ckeditor', array('label' => 'Skrócony opis', 'required' => false))
->add('description', 'ckeditor', array('label' => 'Opis', 'required' => false))
->add('metaTitle', 'text', array('label' => 'Znacznik meta - tytuł', 'required' => false))
->add('metaKeywords', 'textarea', array('label' => 'Znacznik meta - słowa kluczowe', 'required' => false))
->add('metaDescription', 'textarea', array('label' => 'Znacznik meta - opis', 'required' => false))
->add('brands', 'entity', array('label' => 'Producent', 'class' => 'MlBackendBundle:Brands', 'required' => true))
->add('availability', 'entity', array('label' => 'Dostępność', 'class' => 'MlBackendBundle:Availability', 'required' => true))
->add('getCategories', 'entity',
[
'class' => 'Ml\BackendBundle\Entity\Categories',
'property' => 'name',
'multiple' => true,
'expanded' => false,
'label' => 'Kategoria',
])
->add('images', 'collection', array(
'type' => new ImagesType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'label' => ' '))
->add('documents', 'collection', array(
'type' => new DocumentsType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'label' => ' '))
->add('attributes', 'collection', array(
'type' => new AttributesType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
'label' => ' '))
;
}
[/php]