Skip to content

Commit

Permalink
RotationConfigForm: Update only if changes exist
Browse files Browse the repository at this point in the history
  • Loading branch information
sukhwinder33445 committed Jun 24, 2024
1 parent 7b7788e commit 215a532
Showing 1 changed file with 150 additions and 106 deletions.
256 changes: 150 additions & 106 deletions application/forms/RotationConfigForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ class RotationConfigForm extends CompatForm
/** @var ?DateTime The first handoff of a newer version for this rotation */
protected $nextHandoff;

/** @var int The rotation id */
protected $rotationId;

/**
* Set the label for the submit button
*
Expand Down Expand Up @@ -199,112 +202,8 @@ public function __construct(int $scheduleId, Connection $db)
*/
public function loadRotation(int $rotationId): self
{
/** @var ?Rotation $rotation */
$rotation = Rotation::on($this->db)
->filter(Filter::all(
Filter::equal('id', $rotationId),
Filter::equal('deleted', 'n')
))
->first();
if ($rotation === null) {
throw new HttpNotFoundException($this->translate('Rotation not found'));
}

$formData = [
'mode' => $rotation->mode,
'name' => $rotation->name,
'priority' => $rotation->priority,
'schedule' => $rotation->schedule_id,
'options' => $rotation->options
];
if (! self::EXPERIMENTAL_OVERRIDES) {
$formData['first_handoff'] = $rotation->first_handoff;
}

if (self::EXPERIMENTAL_OVERRIDES) {
$getHandoff = function (Rotation $rotation): DateTime {
switch ($rotation->mode) {
case '24-7':
$time = $rotation->options['at'];

break;
case 'partial':
$time = $rotation->options['from'];

break;
case 'multi':
$time = $rotation->options['from_at'];

break;
default:
throw new LogicException('Invalid mode');
}

$handoff = DateTime::createFromFormat('Y-m-d H:i', $rotation->first_handoff . ' ' . $time);
if ($handoff === false) {
throw new ConfigurationError('Invalid date format');
}

return $handoff;
};

$this->previousHandoff = $getHandoff($rotation);

/** @var ?TimeperiodEntry $previousShift */
$previousShift = TimeperiodEntry::on($this->db)
->columns('until_time')
->filter(Filter::all(
Filter::equal('deleted', 'n'),
Filter::equal('timeperiod.deleted', 'n'),
Filter::equal('timeperiod.rotation.schedule_id', $rotation->schedule_id),
Filter::equal('timeperiod.rotation.priority', $rotation->priority),
Filter::unequal('timeperiod.owned_by_rotation_id', $rotation->id),
Filter::lessThanOrEqual('until_time', $this->previousHandoff),
Filter::like('until_time', '*')
))
->orderBy('until_time', SORT_DESC)
->first();
if ($previousShift !== null) {
$this->previousShift = $previousShift->until_time;
}

/** @var ?Rotation $newerRotation */
$newerRotation = Rotation::on($this->db)
->columns(['first_handoff', 'options', 'mode'])
->filter(Filter::all(
Filter::equal('deleted', 'n'),
Filter::equal('schedule_id', $rotation->schedule_id),
Filter::equal('priority', $rotation->priority),
Filter::greaterThan('first_handoff', $rotation->first_handoff)
))
->orderBy('first_handoff', SORT_ASC)
->first();
if ($newerRotation !== null) {
$this->nextHandoff = $getHandoff($newerRotation);
}
}

$membersRes = $rotation
->member
->filter(Filter::equal('deleted', 'n'))
->filter(Filter::any(
Filter::equal('contact.deleted', 'n'),
Filter::equal('contactgroup.deleted', 'n')
))
->orderBy('position', SORT_ASC);

$members = [];
foreach ($membersRes as $member) {
if ($member->contact_id !== null) {
$members[] = 'contact:' . $member->contact_id;
} else {
$members[] = 'group:' . $member->contactgroup_id;
}
}

$formData['members'] = implode(',', $members);

$this->populate($formData);
$this->rotationId = $rotationId;
$this->populate($this->fetchDbValues());

return $this;
}
Expand Down Expand Up @@ -442,6 +341,10 @@ public function editRotation(int $rotationId): void
$transactionStarted = $this->db->beginTransaction();
}

if (! $this->hasChanges()) {
return;
}

// Delay the creation, avoids intermediate constraint failures
$createStmt = $this->createRotation((int) $priority);

Expand Down Expand Up @@ -1592,4 +1495,145 @@ private function calculateRemainingHandoffs(Rule $rrule, DateInterval $shiftDura

return $result;
}

/**
* Fetch the values from the database
*
* @return array
*
* @throws HttpNotFoundException
*/
private function fetchDbValues(): array
{
/** @var ?Rotation $rotation */
$rotation = Rotation::on($this->db)
->filter(Filter::all(
Filter::equal('id', $this->rotationId),
Filter::equal('deleted', 'n')
))
->first();
if ($rotation === null) {
throw new HttpNotFoundException($this->translate('Rotation not found'));
}

$formData = [
'mode' => $rotation->mode,
'name' => $rotation->name,
'priority' => $rotation->priority,
'schedule' => $rotation->schedule_id,
'options' => $rotation->options
];
if (! self::EXPERIMENTAL_OVERRIDES) {
$formData['first_handoff'] = $rotation->first_handoff;
}

if (self::EXPERIMENTAL_OVERRIDES) {
$getHandoff = function (Rotation $rotation): DateTime {
switch ($rotation->mode) {
case '24-7':
$time = $rotation->options['at'];

break;
case 'partial':
$time = $rotation->options['from'];

break;
case 'multi':
$time = $rotation->options['from_at'];

break;
default:
throw new LogicException('Invalid mode');
}

$handoff = DateTime::createFromFormat('Y-m-d H:i', $rotation->first_handoff . ' ' . $time);
if ($handoff === false) {
throw new ConfigurationError('Invalid date format');
}

return $handoff;
};

$this->previousHandoff = $getHandoff($rotation);

/** @var ?TimeperiodEntry $previousShift */
$previousShift = TimeperiodEntry::on($this->db)
->columns('until_time')
->filter(Filter::all(
Filter::equal('deleted', 'n'),
Filter::equal('timeperiod.deleted', 'n'),
Filter::equal('timeperiod.rotation.schedule_id', $rotation->schedule_id),
Filter::equal('timeperiod.rotation.priority', $rotation->priority),
Filter::unequal('timeperiod.owned_by_rotation_id', $rotation->id),
Filter::lessThanOrEqual('until_time', $this->previousHandoff),
Filter::like('until_time', '*')
))
->orderBy('until_time', SORT_DESC)
->first();
if ($previousShift !== null) {
$this->previousShift = $previousShift->until_time;
}

/** @var ?Rotation $newerRotation */
$newerRotation = Rotation::on($this->db)
->columns(['first_handoff', 'options', 'mode'])
->filter(Filter::all(
Filter::equal('deleted', 'n'),
Filter::equal('schedule_id', $rotation->schedule_id),
Filter::equal('priority', $rotation->priority),
Filter::greaterThan('first_handoff', $rotation->first_handoff)
))
->orderBy('first_handoff', SORT_ASC)
->first();
if ($newerRotation !== null) {
$this->nextHandoff = $getHandoff($newerRotation);
}
}

$membersRes = $rotation
->member
->filter(Filter::equal('deleted', 'n'))
->filter(Filter::any(
Filter::equal('contact.deleted', 'n'),
Filter::equal('contactgroup.deleted', 'n')
))
->orderBy('position', SORT_ASC);

$members = [];
foreach ($membersRes as $member) {
if ($member->contact_id !== null) {
$members[] = 'contact:' . $member->contact_id;
} else {
$members[] = 'group:' . $member->contactgroup_id;
}
}

$formData['members'] = implode(',', $members);

return $formData;
}

/**
* Whether the form has changes
*
* @return bool
*/
public function hasChanges(): bool
{
$values = $this->getValues();
$values['members'] = $this->getValue('members');

// only keys that are present in $values
$dbValuesToCompare = array_intersect_key($this->fetchDbValues(), $values);

$checker = static function ($a, $b) use (&$checker) {
if (! is_array($a) || ! is_array($b)) {
return $a <=> $b;
}

return empty(array_udiff_assoc($a, $b, $checker)) ? 0 : 1;
};

return ! empty(array_udiff_assoc($values, $dbValuesToCompare, $checker));
}
}

0 comments on commit 215a532

Please sign in to comment.