#php #symfony #symfony4 #php-7
#php #symfony #symfony4 #php-7
Вопрос:
Я работаю над проектом symfony 4. У меня есть форма, которая содержит CollectionType сущностей. Моя цель — добавить записи в эту коллекцию. Но когда я пытаюсь отправить форму, я получаю эту ошибку:
Expected argument of type "AppEntitySessionLevels", "array" given at property path "session_levels"
Я следовал этой документации: https://symfony.com/doc/4.4/form/form_collections.html
и еще : https://symfony.com/doc/current/reference/forms/types/collection.html#allow-add
Когда я сбрасываю то, что отправляется через отправку, я получаю исходные записи как объекты SessionLevels, но новая запись отправляется как массив, который не может быть обработан. Как я могу отправить свою новую запись в коллекцию как сущность, а не как массив?
Вот моя основная форма :
class ModifySessionForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('date', DateType::class, [
'label' => 'Date de la session',
'attr' => [
'class' => 'w-100'
]
])
->add('circuit', EntityType::class, [
'choice_label' => 'name',
'class' => Circuit::class,
'label'=>false,
'attr' => ['class' => 'd-none'],
])
->add('session_levels', CollectionType::class, [
'entry_type' => SessionLevelType::class,
'entry_options' => [
'label' => false
],
'label' => 'Niveaux',
'allow_add'=> true,
'by_reference' => false,
'allow_delete' => true,
'attr' => [
'class' => 'w-100'
]
])
->add('submit', SubmitType::class, [
'label' => 'Valider',
'attr' => [
'class' => 'btn btn-lrt w-100 mt-3'
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => SessionDetails::class
]);
}
}
Вот моя встроенная форма: SessionLevelType.php
class SessionLevelType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('level', TextType::class, [
'label' => false,
'attr' => [
'class' => 'w-100'
]
])
->add('duration', TextType::class, [
'label' => false,
'attr' => [
'class' => 'w-100'
]
])
->add('number_of_participants', NumberType::class, [
'label' => false,
'html5' => true,
'attr' => [
'class' => 'w-100',
'min' => '0'
]
])
->add('price', NumberType::class, [
'label' => false,
'html5' => true,
'attr' => [
'class' => 'w-100',
'min' => '0',
'step' => '0.01'
]
])
;
}
}
И вот мой метод контроллера :
/**
* @Route("/session/modify/{id}", name="admin_session_modify", requirements={"id": "d "})
* @param Request $request
* @param SessionDetails $sessionInModif
* @param CircuitRepository $circuitRepo
* @param AdminSessionService $SessionService
* @return Response
* @IsGranted("IS_AUTHENTICATED_REMEMBERED")
*/
public function modifySession(Request $request,SessionDetails $sessionInModif,CircuitRepository $circuitRepo,AdminSessionService $SessionService)
{
$form = $this->createForm(ModifySessionForm::class, $sessionInModif);
$form->handleRequest($request);
//handle form submition
if($form->isSubmitted() amp;amp; $form->isValid()) {
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($sessionInModif);
$entityManager->flush();
}
return $this->render('admin/sessions/modifSession.html.twig',[
'form' => $form->createView(),
'session' =>$sessionInModif,
'circuits' => $circuitRepo->findAll()
]);
}
Наконец, вот HTML и JS, которые связаны с материалом коллекции:
<tbody class="session_levels" data-prototype="{{ form_widget(form.session_levels.vars.prototype)|e('html_attr') }}">
{% for lvl in form.session_levels %}
<tr>
<td>{{ form_row(lvl.level) }}</td>
<td>{{ form_row(lvl.duration) }}</td>
<td>{{ form_row(lvl.number_of_participants) }}</td>
<td>{{ form_row(lvl.price) }}</td>
<td><button type="button" style="border:none;" onClick="handleDeleteLvlEntry()"><i class="fas fa-trash-alt"></i></button></td>
</tr>
<script>levelsIdx ;</script>
{% endfor %}
<tr id="inserterRow">
<td></td>
<td></td>
<td></td>
<td></td>
<td><button type="button" class="add_item_link" data-collection-holder-class="session_levels" style="border:none"><i class="fas fa-plus-square"></i></button></td>
</tr>
</tbody>
</table>
{{ form_row(form.session_levels) }}
</div>
{{ form_row(form.submit) }}
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
$(document).ready(function() {
var $levelsCollectionHolder = $('tr.session_levels');
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$levelsCollectionHolder.data('index', levelsIdx);
$('body').on('click', '.add_item_link', function(e) {
var $collectionHolderClass = $(e.currentTarget).data('collectionHolderClass');
// add a new tag form (see next code block)
addFormToCollection($collectionHolderClass);
});
});
function addFormToCollection($collectionHolderClass) {
// Get the ul that holds the collection of tags
var $collectionHolder = $('.' $collectionHolderClass);
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
if(index == undefined)
index = levelsIdx;
console.log(index)
var newForm = prototype;
// You need this only if you didn't set 'label' => false in your tags field in TaskType
// Replace '__name__label__' in the prototype's HTML to
// instead be a number based on how many items we have
//newForm = newForm.replace(/__name__label__/g, levelsIdx);
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
newForm = newForm.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index 1);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<tr></tr>').append(newForm.replace(/div/g,'td') '<td><button type="button" style="border:none;" onClick="handleDeleteLvlEntry()"><i class="fas fa-trash-alt"></i></button></td>');
// Add the new form at the end of the list
/*
*/
$collectionHolder.append($newFormLi);
$('#modify_session_form_session_levels_' index).addClass('d-none');
levelsIdx ;
index ;
//move the inserting row to the bottom
$("#inserterRow").clone().appendTo("#levelsTable");
$("#inserterRow").remove();
}
Комментарии:
1. добавьте configureOptions с data_class SessionLevel(s) к вашему типу SessionLevelType, в противном случае этот тип формы будет создавать массивы
2. @Jakumi спасибо, что это было так. Это выдавало мне ошибку, но я просто забыл добавить оператор use для sessionLevels в SessionLevelType . В любом случае спасибо!