Skip to content

Instantly share code, notes, and snippets.

@webdevilopers
Last active August 29, 2015 14:07
Show Gist options
  • Select an option

  • Save webdevilopers/42c3cdc6013fb09f1c58 to your computer and use it in GitHub Desktop.

Select an option

Save webdevilopers/42c3cdc6013fb09f1c58 to your computer and use it in GitHub Desktop.
Batch resp. mass editing symfony form type using Doctrine Entity using data transformation and events
<form action="#" method="post" >
<input type="hidden" id="contract_timekeeping_entry_batch__token" name="contract_timekeeping_entry_batch[_token]" value="U8W2Zy-AfwOC_UX7mOUqI7PGpn69Vo-X8UnjM07BuNQ" />
<button type="submit" id="contract_timekeeping_entry_batch_submit" name="contract_timekeeping_entry_batch[submit]">Submit</button>
<div id='timekeepings'>
<table class='default wide' border="1">
<thead>
<tr>
<th>Personal</th>
<th>&nbsp;</th>
<th class='unimportant' colspan='2'>28.11.2011</th>
<th class='unimportant' colspan='2'>29.11.2011</th>
<th class='unimportant' colspan='2'>30.11.2011</th>
<th class='unimportant' colspan='2'>01.12.2011</th>
<th class='unimportant' colspan='2'>02.12.2011</th>
<th class='unimportant' colspan='2'>03.12.2011</th>
<th class='unimportant' colspan='2'>04.12.2011</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody class='single-row'>
<tr class='work' row_idx='0'>
<th class='user' rowspan='2' user_id='170'>
<div>
<strong> <label class="required">170</label></strong>
<img alt="Add" class="add clickable" onclick="add_row(170)" src="/images/add.png" title="Weitere Zeile hinzufügen" />
</div>
</th>
<th class='title_work'>Zeit von/bis</th>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-28_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-28][work_begin]" value="1112" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-28_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-28][work_end]" value="1211" /></td>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-29_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-29][work_begin]" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-29_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-29][work_end]" /></td>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-30_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-30][work_begin]" value="1100" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-30_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-30][work_end]" value="1300" /></td>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-01_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-01][work_begin]" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-01_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-01][work_end]" /></td>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-02_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-02][work_begin]" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-02_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-02][work_end]" /></td>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-03_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-03][work_begin]" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-03_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-03][work_end]" /></td>
<td class="work_begin"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-04_work_begin" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-04][work_begin]" /></td>
<td class="work_end"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-04_work_end" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-04][work_end]" /></td>
<th class='sum' title='Arbeitszeit'>
<span></span>
</th>
</tr>
<tr class='travel' row_idx='0'>
<th class='title_other'>Fahrt/Pause</th>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-28_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-28][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-28_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-28][duration_break]" size="5" /></td>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-29_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-29][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-29_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-29][duration_break]" size="5" /></td>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-30_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-30][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-11-30_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-30][duration_break]" size="5" /></td>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-01_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-01][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-01_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-01][duration_break]" size="5" /></td>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-02_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-02][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-02_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-02][duration_break]" size="5" /></td>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-03_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-03][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-03_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-03][duration_break]" size="5" /></td>
<td class="duration_travel"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-04_duration_travel" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-04][duration_travel]" size="5" /></td>
<td class="duration_break"><input type="text" id="contract_timekeeping_entry_batch_timekeepingEntries_170_days_2011-12-04_duration_break" name="contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-12-04][duration_break]" size="5" /></td>
<th class='sum' title='Fahrtzeit'>
<div>
<span></span>
<img alt="Cross" class="delete clickable" src="/images/cross.png?1396860297" />
</div>
</th>
</tr>
</tbody>
<tfoot>
<tr class='work'>
<th>&nbsp;</th>
<th class='title_work'>Arbeitszeit</th>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<th class='sum'>0</th>
</tr>
<tr class='travel'>
<th>&nbsp;</th>
<th class='title_other'>Fahrtzeit</th>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<th class='sum'>0</th>
</tr>
</tfoot>
</table>
</div>
</form>
{% extends "PlusquamContractBundle::layout.html.twig" %}
{% block content %}
<form action="#" method="post" {{ form_enctype(form) }}>
{{ form_widget(form._token) }}
{{ form_errors(form) }}
{{ form_widget(form.submit) }}
<div id='timekeepings'>
<table class='default wide' border="1">
<thead>
<tr>
<th>Personal</th>
<th>&nbsp;</th>
{% for day in days %}
<th class='unimportant' colspan='2'>{{ day|localizeddate('medium', 'none') }}</th>
{% endfor %}
<th>&nbsp;</th>
</tr>
</thead>
{% for user in form.timekeepingEntries %}
<tbody class='single-row'>
<tr class='work' row_idx='0'>
<th class='user' rowspan='2' user_id='{{ user.vars.name }}'>
<div>
<strong>{{ form_label(user) }}</strong>
<img alt="Add" class="add clickable" onclick="add_row({{ user.vars.name }})" src="/images/add.png" title="Weitere Zeile hinzufügen" />
</div>
</th>
<th class='title_work'>Zeit von/bis</th>
{% for day in user.days %}
<td class="work_begin">{{ form_widget(day.work_begin) }}</td>
<td class="work_end">{{ form_widget(day.work_end) }}</td>
{% endfor %}
<th class='sum' title='Arbeitszeit'>
<span></span>
</th>
</tr>
<tr class='travel' row_idx='0'>
<th class='title_other'>Fahrt/Pause</th>
{% for day in user.days %}
<td class="duration_travel">{{ form_widget(day.duration_travel) }}</td>
<td class="duration_break">{{ form_widget(day.duration_break) }}</td>
{% endfor %}
<th class='sum' title='Fahrtzeit'>
<div>
<span></span>
<img alt="Cross" class="delete clickable" src="/images/cross.png?1396860297" />
</div>
</th>
</tr>
</tbody>
{% endfor %}
<tfoot>
<tr class='work'>
<th>&nbsp;</th>
<th class='title_work'>Arbeitszeit</th>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<th class='sum'>0</th>
</tr>
<tr class='travel'>
<th>&nbsp;</th>
<th class='title_other'>Fahrtzeit</th>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<td colspan='2'>&nbsp;</td>
<th class='sum'>0</th>
</tr>
</tfoot>
</table>
</div>
</form>
{% include 'PlusquamTimekeepingBundle:Timekeeping:_script.html.twig' %}
{% endblock %}
<?php
namespace Plusquam\Bundle\ContractBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Contract
{
/**
* @ORM\OneToMany(targetEntity="TimekeepingEntry", mappedBy="contract", cascade={"persist"})
*/
private $timekeepingEntries;
/**
* Add timekeepingEntries
*
* @param \Plusquam\Bundle\ContractBundle\Entity\TimekeepingEntry $timekeepingEntries
* @return Contract
*/
public function addTimekeepingEntry(\Plusquam\Bundle\ContractBundle\Entity\TimekeepingEntry $timekeepingEntries)
{
$timekeepingEntries->setContract($this);
$this->timekeepingEntries[] = $timekeepingEntries;
return $this;
}
/**
* Remove timekeepingEntries
*
* @param \Plusquam\Bundle\ContractBundle\Entity\TimekeepingEntry $timekeepingEntries
*/
public function removeTimekeepingEntry(\Plusquam\Bundle\ContractBundle\Entity\TimekeepingEntry $timekeepingEntries)
{
$this->timekeepingEntries->removeElement($timekeepingEntries);
}
/**
* Get timekeepingEntries
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getTimekeepingEntries()
{
return $this->timekeepingEntries;
}
}
<?php
namespace Acme\Bundle\TimekeepingBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Acme\Bundle\ContractBundle\Entity\TimekeepingEntry;
use Acme\Bundle\TimekeepingBundle\Form\TimekeepingEntryType;
class TimekeepingController extends Controller
{
/**
* @Route("/timekeeping/edit/{id}")
* @Template()
*/
public function batchAction(Request $request)
{
$contractId = $request->get('contractId');
$em = $this->getDoctrine()->getManager();
$weekStartDate = $this->get('request')->get('date') !== null
? $this->get('request')->get('date')
: '28.11.2011';
$monthStartDate = '28.11.2014';
$weekParam = $this->get('request')->get('week');
$date = new \DateTime($weekStartDate);
$week = $date->format("W");
$days = $this->daysInWeek($week, $year);
$contract = $em->getRepository('Plusquam\Bundle\ContractBundle\Entity\TimekeepingEntry')
->findContractTimekeepingEntriesByDate(array('contractId' => $contractId, 'days' => $days));
$form = $this->createForm('contract_timekeeping_entry_batch', $contract, array('days' => $days));
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($contract);
$em->flush();
}
return array(
'form' => $form->createView(),
'days' => $days,
'week_start_date' => $weekStartDate,
'month_start_date' => $monthStartDate
);
}
}
<?php
namespace Acme\Bundle\ContractBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="Acme\Bundle\ContractBundle\Entity\TimekeepingEntryRepository")
* @ORM\Table(name="timekeeping_entries")
*/
class TimekeepingEntry
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Contract", inversedBy="timekeepingEntries")
* @ORM\JoinColumn(name="contract_id", referencedColumnName="id")
*/
private $contract;
/**
* @ORM\Column(type="date")
*/
private $date;
/**
* @ORM\Column(type="smallint", name="work_begin", options={"unsigned":true}, columnDefinition="SMALLINT(4) UNSIGNED ZEROFILL")
*/
private $workBegin;
/**
* @ORM\Column(type="smallint", name="work_end", options={"unsigned":true}, columnDefinition="SMALLINT(4) UNSIGNED ZEROFILL") // type time?
*/
private $workEnd;
/**
* @ORM\ManyToOne(targetEntity="Application\Sonata\UserBundle\Entity\User", inversedBy="timekeepingEntries")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
}
<?php
namespace Plusquam\Bundle\ContractBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Plusquam\Bundle\ContractBundle\Form\DataTransformer\TimekeepingTransformer;
class TimekeepingEntryBatchType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$timekeepingTransformer = new TimekeepingTransformer();
$builder
->setAttribute('days', $options['days'])
->add('submit', 'submit', array())
->addModelTransformer($timekeepingTransformer) // On preSetData data send to the event is not processed by modelTransformer.
;
// desired notation: contract_timekeeping_entry_batch[timekeepingEntries][1][work_end]
// $builder->add('timekeepingEntries', 'collection', array(
// // each item in the array will be an "email" field
//// 'type' => 'TimekeepingEntryType',
// 'type' => new TimekeepingEntryType(),
// // these options are passed to each "email" type
// 'allow_delete' => true,
// 'allow_add' => true,
// 'by_reference' => false,
// 'options' => array(
// 'min_date' => reset($options['days']),
// 'max_date' => end($options['days']),
//// 'required' => false,
//// 'attr' => array('class' => 'email-box')
// ),
// ));
$factory = $builder->getFormFactory();
$formModifier = function (FormInterface $form, $contract) use ($factory, $options) {
$timekeepingEntries = $contract->getTimekeepingEntries();
// current notation: contract_timekeeping_entry_batch[timekeepingEntries][170][days][2011-11-28][work_begin]
$usersBuilder = $factory->createNamed('timekeepingEntries', 'form', array(), array(
// $usersBuilder = $factory->createNamed('timekeepingEntries', 'collection', array(), array(
'auto_initialize' => false
))
;
$form->add($usersBuilder);
if (count($timekeepingEntries) == 0) {
return;
}
$data = array(
'timekeepings' => array(
'users' => array(),
),
'days' => $options['days']
);
foreach ($timekeepingEntries as $timekeeping) {
$user = $timekeeping->getUser()->getId();
$date = $timekeeping->getDate();
$data['timekeepings']['users'][$user]['days'][$date->format('Y-m-d')]['work_begin'] = $timekeeping->getWorkBegin();
$data['timekeepings']['users'][$user]['days'][$date->format('Y-m-d')]['work_end'] = $timekeeping->getWorkEnd();
$data['timekeepings']['users'][$user]['days'][$date->format('Y-m-d')]['duration_travel'] = $timekeeping->getDurationTravel();
$data['timekeepings']['users'][$user]['days'][$date->format('Y-m-d')]['duration_break'] = $timekeeping->getDurationBreak();
}
foreach ($data['timekeepings']['users'] as $userId => $user) {
$userBuilder = $factory->createNamed((string) $userId, 'form', $user, array(
// $userBuilder = $factory->createNamed(null, 'form', $user, array(
'auto_initialize' => false
));
$daysBuilder = $factory->createNamed('days', 'form', $user['days'], array(
'auto_initialize' => false
));
$userBuilder->add($daysBuilder);
foreach ($data['days'] as $weekDay => $date) {
$formData = key_exists($date, $user['days']) ? $user['days'][$date] : null;
$dateBuilder = $factory->createNamed($date, 'form', $formData, array(
'auto_initialize' => false
));
$dateBuilder->add('work_begin' , 'text', array(
'required' => false,
));
$dateBuilder->add('work_end' , 'text', array(
'required' => false,
));
$dateBuilder->add('duration_travel' , 'number', array(
'precision' => 2,
'required' => false,
'label' => 'Travael',
'attr' => array('size' => 5)
)); // @see http://symfony.com/doc/master/reference/forms/types/number.html#field-options
$dateBuilder->add('duration_break' , 'number', array(
'precision' => 2,
'required' => false,
'label' => 'Break',
'attr' => array('size' => 5)
));
$daysBuilder->add($dateBuilder);
}
$usersBuilder->add($userBuilder);
}
};
$builder->addEventListener(FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$contract = $event->getData();
$formModifier($event->getForm(), $contract);
}
);
$builder->addEventListener(FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$contract = $event->getData();
$formModifier($event->getForm(), $contract);
}
);
}
/**
* {@inheritDoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['days'] = $options['days'];
}
/**
*
* @param type $weekNum
* @param type $year
* @return type
* @todo Move to helper
*/
function daysInWeek($weekNum, $year)
{
$result = array();
$datetime = new \DateTime('00:00:00');
$datetime->setISODate($year, $weekNum, 1); // start with monday
$interval = new \DateInterval('P1D');
$week = new \DatePeriod($datetime, $interval, 6); // count of days in week
foreach($week as $day){
$dateIndex = $day->format('w');
$result[$dateIndex] = $day->format('Y-m-d');
}
return $result;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Plusquam\Bundle\ContractBundle\Entity\Contract',
'days' => array()
));
}
/**
* @return string
*/
public function getName()
{
return 'contract_timekeeping_entry_batch';
}
}
<?php
namespace Acme\Bundle\TimekeepingBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TimekeepingEntryType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('date', 'date', array(
'widget' => 'choice',
'attr' => array('class' => 'date')
)) // will be hidden
//->add('user') // will be hidden
->add('work_begin')
->add('work_end')
->add('submit', 'submit');
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\Bundle\ContractBundle\Entity\TimekeepingEntry'
));
}
/**
* @return string
*/
public function getName()
{
return 'timekeeping';
}
}
<?php
namespace Acme\AppBundle\ContractBundle\Form\DataTransformer;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class TimekeepingTransformer implements DataTransformerInterface
{
/**
* @param Contract|null $contract
* @return string
*/
public function transform($contract)
{
// no need for transforming, populating is done dynamically by the PRE_SET_DATA event
return $contract;
}
/**
* Transforms a timekeepings collection array back to TimekeepingEntry Entity type
*
* @return Contract|null
*
* @throws TransformationFailedException if object (issue) is not found.
*/
public function reverseTransform($contract)
{
// What to do here? Never called using PRE_SET_DATA event?
return $contract;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment