addModelTransformer(new CallbackTransformer( function ($value) { // page is loaded, nothing to do if (!$value instanceof QuickEntryWeek) { return $value; } foreach ($value->getRows() as $row) { foreach ($row->getTimesheets() as $timesheet) { foreach ($timesheet->getMetaFields() as $metaField) { $row->setMetaFieldValue($metaField); } } } return $value; }, function (?QuickEntryWeek $value) { if ($value === null) { return null; } foreach ($value->getRows() as $row) { $project = $row->getProject(); $activity = $row->getActivity(); if ($project === null || $activity === null) { continue; } foreach ($row->getTimesheets() as $timesheet) { $timesheet->setProject($project); $timesheet->setActivity($activity); foreach ($row->getMetaFields() as $metaField) { if (null === ($name = $metaField->getName())) { continue; } if (null === $timesheet->getMetaField($name)) { $timesheet->setMetaField($metaField); } if (null === ($tmpField = $timesheet->getMetaField($name))) { continue; } if ($tmpField->getValue() !== $metaField->getValue()) { $tmpField->setValue($metaField->getValue()); $timesheet->markAsModified(); } } } } return $value; } )); $builder->add('rows', CollectionType::class, [ 'label' => false, 'entry_type' => QuickEntryWeekType::class, 'entry_options' => [ 'label' => false, 'duration_minutes' => $this->configuration->getTimesheetIncrementDuration(), // this is NOT the start_date, because it would prevent projects from appearing // in the first days of the week, if the projects ends at the end of the week // the validation still triggers if the user selects days outside the project range 'start_date' => $options['end_date'], 'end_date' => $options['end_date'], 'empty_data' => function (FormInterface $form) use ($options) { return clone $options['prototype_data']; }, 'prototype_data' => clone $options['prototype_data'], ], 'prototype_data' => $options['prototype_data'], 'allow_add' => true, 'constraints' => [ new Valid(), new All(['constraints' => [new QuickEntryModel()]]) ], ]); } public function configureOptions(OptionsResolver $resolver): void { $start = new \DateTime(); $start->setTime(0, 0, 0); $end = clone $start; $end->add(new \DateInterval('P1W')); $end->setTime(23, 59, 59); $resolver->setDefaults([ 'csrf_protection' => true, 'csrf_field_name' => '_token', 'csrf_token_id' => 'timesheet_quick_edit', 'data_class' => QuickEntryWeek::class, 'timezone' => date_default_timezone_get(), 'start_date' => $start, 'end_date' => $end, 'prototype_data' => null, ]); } }