Created
August 29, 2016 13:34
-
-
Save anonymous/f1b44c6c9f8dea45a2ed145bd81a993f to your computer and use it in GitHub Desktop.
Řešení pro chybějící sportoviště
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{block scripts} | |
{include parent} | |
<script> | |
(function ($) { | |
$(function () { | |
var reservationsTable = $('#table-of-reservations'); | |
var refreshUrl = reservationsTable.data('url'); | |
var refreshRate = reservationsTable.data('refreshRate'); | |
var automaticallyRefreshTable = reservationsTable.data('automaticallyRefreshTable'); | |
if (automaticallyRefreshTable == true) { | |
setInterval(function () { | |
$.nette.ajax({ | |
method: 'GET', | |
url: refreshUrl | |
}); | |
}, refreshRate); | |
} | |
}); | |
})(window.jQuery); | |
</script> | |
{/block} | |
{block content} | |
<header> | |
<div class="container-fluid"> | |
<div class="row"> | |
<div class="col-xs-6 title"> | |
<h1> | |
<i class="fa fa-clock-o"></i> | |
<span>Rezervace</span> | |
</h1> | |
</div> | |
<div class="col-xs-6 text-right tools"> | |
</div> | |
</div> | |
</div> | |
</header> | |
{if $calendar != true} | |
{var $previousDay = $displayedDate->modify('-1 day')} | |
{var $nextDay = $displayedDate->modify('+1 day')} | |
<div class="container-fluid"> | |
<div class="row reservations-navigation"> | |
<div class="col-xs-3"> | |
<a href="{link previousDay!}" class="btn btn-default"> | |
<i class="fa fa-chevron-left"></i> | |
<small>{$previousDay|completeDate}</small> | |
</a> | |
</div> | |
<div class="col-xs-6 text-center today"> | |
<strong>{$displayedDate|completeDate}</strong> | |
</div> | |
<div class="col-xs-3 text-right"> | |
<a href="{link nextDay!}" class="btn btn-default"> | |
<small>{$nextDay|completeDate}</small> | |
<i class="fa fa-chevron-right"></i> | |
</a> | |
</div> | |
</div> | |
{control sportsFieldsOverview} | |
</div> | |
<div class="modal fade" tabindex="-1" role="dialog" id="reservation_form"> | |
<div class="modal-dialog modal-w-66"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> | |
<h4 class="modal-title"> | |
{snippet modalTitle} | |
{if $chosenSportsField !== null} | |
{$chosenSportsField->getName()} | |
{else} | |
Sportoviště nenalezeno | |
{/if} | |
{/snippet} | |
</h4> | |
</div> | |
<div class="modal-body"> | |
{snippet modalBody} | |
{if $chosenSportsField !== null} | |
{control sportsFieldReservation} | |
{else} | |
<p>Vybrané sportoviště nebylo nalezeno</p> | |
{/if} | |
{/snippet} | |
</div> | |
<div class="modal-footer"></div> | |
</div> | |
</div> | |
</div> | |
{else} | |
<a href="{plink this, calendar => null}">zpět</a> | |
{control calendar} | |
{/if} | |
{/block} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Reservations\Presenters; | |
use Reservations\Components\ISportsFieldReservationControlFactory; | |
use Reservations\Components\ISportsFieldsOverviewControlFactory; | |
use blitzik\Calendar\Factories\HorizontalCalendarCellFactory; | |
use App\OperationModule\Presenters\OperationBasePresenter; | |
use Reservations\Components\SportsFieldReservationControl; | |
use Reservations\Components\SportsFieldsOverviewControl; | |
use Reservations\Components\ReservationCalendarControl; | |
use Reservations\Components\SportsFieldRowControl; | |
use blitzik\Calendar\Generator\CalendarGenerator; | |
use Reservations\Facades\ReservationFacade; | |
use Reservations\Facades\SportsFieldFacade; | |
use Reservations\Queries\SportsFieldQuery; | |
use blitzik\Calendar\Calendar; | |
use Reservations\Reservation; | |
use Reservations\SportsField; | |
class ReservationPresenter extends OperationBasePresenter | |
{ | |
/** @persistent */ | |
public $year; | |
/** @persistent */ | |
public $month; | |
/** @persistent */ | |
public $day; | |
/** @persistent */ | |
public $chosenSportsFieldId; | |
/** @persistent */ | |
public $calendar; | |
/** @persistent */ | |
public $reservationId; | |
/** @persistent */ | |
public $clickedHour; | |
/** | |
* @var ISportsFieldReservationControlFactory | |
* @inject | |
*/ | |
public $sportsFieldReservationControlFactory; | |
/** | |
* @var ISportsFieldsOverviewControlFactory | |
* @inject | |
*/ | |
public $sportsFieldOverviewControlFactory; | |
/** | |
* @var ReservationFacade | |
* @inject | |
*/ | |
public $reservationFacade; | |
/** | |
* @var SportsFieldFacade | |
* @inject | |
*/ | |
public $sportsFieldFacade; | |
/** @var Reservation */ | |
private $reservation; | |
/** @var SportsField[] */ | |
private $sportsFields; | |
/** @var SportsField */ | |
private $sportsField; | |
/** @var \DateTime */ | |
private $date; | |
private $automaticallyRefreshReservationTable = false; | |
private $reservationTableRefreshRate = 35000; // in ms | |
protected function startup() | |
{ | |
parent::startup(); | |
$this->reservationFacade->removePendingReservations(); | |
} | |
public function actionDefault() | |
{ | |
$this['pageTitle']->setPageTitle('Rezervace sportovišť'); | |
} | |
public function renderDefault() | |
{ | |
if ($this->sportsFields === null) { | |
$this->sportsFields = $this->findSportsFields(); | |
} | |
if ($this->sportsField === null) { | |
if ($this->chosenSportsFieldId !== null) { | |
if (isset($this->sportsFields[$this->chosenSportsFieldId])) { | |
$this->sportsField = $this->sportsFields[$this->chosenSportsFieldId]; | |
} else { | |
$this->sportsField = $this->sportsFieldFacade | |
->getSportsFieldById($this->chosenSportsFieldId); | |
} | |
} | |
} | |
// ----- | |
$this->template->chosenSportsField = $this->sportsField; | |
// ----- | |
$this->template->displayedDate = $this->date; | |
$this->template->calendar = $this->calendar; | |
} | |
protected function createComponentSportsFieldsOverview() | |
{ | |
if ($this->sportsFields === null) { | |
$this->sportsFields = []; | |
} | |
$comp = $this->sportsFieldOverviewControlFactory | |
->create( | |
$this->date, | |
$this->sportsFields | |
); | |
$comp->setTableRefreshRate($this->reservationTableRefreshRate); | |
if ($this->automaticallyRefreshReservationTable === false) { | |
$comp->doNotRefreshTable(); | |
} | |
$comp->onFreeTimeClick[] = [$this, 'onSportsFieldFreeTimeClick']; | |
$comp->onReservedTimeClick[] = [$this, 'onSportsFieldReservedTimeClick']; | |
return $comp; | |
} | |
public function onSportsFieldFreeTimeClick( | |
SportsFieldsOverviewControl $sportsFieldsOverviewControl, | |
SportsFieldRowControl $sportsFieldRowControl, | |
SportsField $sportsField = null, | |
\DateTimeImmutable $clickedHour | |
) { | |
if ($sportsField !== null) { | |
$this->chosenSportsFieldId = $sportsField->getId(); | |
$this->sportsField = $sportsField; | |
$this->sportsFields[$sportsField->getId()] = $sportsField; | |
} else { | |
$this->chosenSportsFieldId = null; // we won't load sportsField in render method | |
$this->sportsFields = []; // do not load sportsFields in render method | |
} | |
$this->clickedHour = $clickedHour->format('H:i'); | |
$this->redrawControl('modalTitle'); | |
$this->redrawControl('modalBody'); | |
} | |
public function onSportsFieldReservedTimeClick( | |
SportsFieldsOverviewControl $sportsFieldsOverviewControl, | |
SportsFieldRowControl $sportsFieldRowControl, | |
SportsField $sportsField, | |
Reservation $reservation | |
) { | |
// todo | |
$this->redrawControl('modalTitle'); | |
$this->redrawControl('modalBody'); | |
} | |
protected function createComponentSportsFieldReservation() | |
{ | |
if ($this->sportsField === null) { | |
$this->sportsField = $this->sportsFieldFacade->getSportsFieldById($this->chosenSportsFieldId); | |
$this->sportsFields = []; | |
if ($this->sportsField !== null) { | |
$this->sportsFields[$this->chosenSportsFieldId] = $this->sportsField; | |
} | |
} | |
$comp = $this->sportsFieldReservationControlFactory | |
->create($this->date, $this->sportsField); | |
if ($this->clickedHour !== null) { | |
$comp->setClickedHour($this->clickedHour); | |
} | |
if ($this->reservation !== null) { | |
$comp->setReservation($this->reservation); | |
} | |
$comp->onParticipantResetting[] = function () { | |
$this->reservationId = null; | |
}; | |
$comp->onMissingSportsField[] = [$this, 'onMissingSportsField']; | |
$comp->onSuccessfulReservationCreation[] = [$this, 'onSuccessfulReservationCreation']; | |
return $comp; | |
} | |
public function onSuccessfulReservationCreation(SportsFieldReservationControl $control, SportsField $sportsField) | |
{ | |
$this->sportsField = null; | |
$this->sportsFields = []; | |
$this['sportsFieldsOverview']['sportsFieldRow'][$sportsField->getId()]->redrawControl(); | |
} | |
public function onMissingSportsField(SportsFieldReservationControl $control) | |
{ | |
$this->chosenSportsFieldId = null; | |
$this->sportsField = null; | |
$this->sportsFields = $this->findSportsFields(); | |
$this['sportsFieldsOverview']->setSportsFields($this->sportsFields); | |
$this['sportsFieldsOverview']->redrawControl(); | |
} | |
public function handleBackToOverview() | |
{ | |
$this->reservationId = null; | |
$this->redirect(':Reservations:Reservation:default'); | |
} | |
/** | |
* @return SportsField[] | |
*/ | |
private function findSportsFields() | |
{ | |
return $this->sportsFieldFacade | |
->findSportsFields( | |
(new SportsFieldQuery()) | |
->notFrozen() | |
->indexById() | |
)->toArray(); | |
} | |
// ---- calendar | |
protected function createComponentCalendar() | |
{ | |
$calendar = new ReservationCalendarControl(Calendar::LANG_CS); | |
$calendar->setCalendarGenerator( | |
new CalendarGenerator(new HorizontalCalendarCellFactory(Calendar::MONDAY)) | |
); | |
$calendar->setMonth($this->month); | |
$calendar->setYear($this->year); | |
$calendar->truncateDaysLabelsTo(2); | |
$calendar->onDaySelection[] = [$this, 'onDaySelection']; | |
return $calendar; | |
} | |
public function onDaySelection($year, $month, $day) | |
{ | |
$this->year = $year; | |
$this->month = $month; | |
$this->day = $day; | |
$this->calendar = null; | |
$this->redirect('this'); | |
} | |
public function handleShowCalendar() | |
{ | |
$this->calendar = true; | |
$this->redirect('this'); | |
} | |
public function handlePreviousDay() | |
{ | |
$date = $this->date->modify('-1 day'); | |
$this->refreshDateProperties($date); | |
} | |
public function handleNextDay() | |
{ | |
$date = $this->date->modify('+1 day'); | |
$this->refreshDateProperties($date); | |
} | |
private function refreshDateProperties(\DateTimeInterface $date) | |
{ | |
$this->year = $date->format('Y'); | |
$this->month = $date->format('n'); | |
$this->day = $date->format('j'); | |
$this->redirect('this'); | |
} | |
// ----- | |
public function loadState(array $params) | |
{ | |
parent::loadState($params); | |
$dateTime = $this->createDateTime($this->year, $this->month, $this->day); | |
if ($dateTime === false) { | |
$dateTime = \DateTimeImmutable::createFromFormat('!Y-n-j', date('Y-n-j')); | |
} | |
$this->year = $dateTime->format('Y'); | |
$this->month = $dateTime->format('n'); | |
$this->day = $dateTime->format('j'); | |
$this->date = $dateTime; | |
} | |
/** | |
* @param int $year | |
* @param int $month | |
* @param int $day | |
* @return \DateTimeImmutable | |
*/ | |
private function createDateTime($year, $month, $day) | |
{ | |
return \DateTimeImmutable::createFromFormat('!Y-n-j', date(sprintf('%s-%s-%s', $year, $month, $day))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{snippet flashMessages} | |
{control flashMessages} | |
{/snippet} | |
{snippet selection} | |
{if $sportsField === null} | |
<p>Vybrané sportoviště nebylo nalezeno</p> | |
{else} | |
<h3>{$day|completeDate}</h3> | |
{if $reservation !== null} | |
<h4>Změna počtu účastníků</h4> | |
{/if} | |
{if $billSelection === true} | |
{include #typeSelection} | |
{else} | |
{if $chosenBillId !== null} | |
<a href="{link intoExistingBill!}" class="ajax">zpět na výběr účtenky</a> | |
{if $bill === null or $bill->isClosed()} | |
<p>Zvolená účtenka byla uzavřena nebo neexistuje</p> | |
{else} | |
{if $repeatableReservation === false and $singleReservation === false} | |
{include #reservationTypeSelection} | |
{elseif $singleReservation === true and $repeatableReservation === false} | |
{control reservationForm} | |
{elseif $repeatableReservation == true and $singleReservation === false} | |
{control repeatableReservationForm} | |
{else} | |
{include #reservationTypeSelection} | |
{/if} | |
{/if} | |
{elseif $intoNewBill === false} | |
{include #back} | |
<h4>Výběr účtenky</h4> | |
{if empty($bills)} | |
<p>Nemáte žádné otevřené účtenky. <a href="{link intoNewBill!}" class="ajax">Vytvořit rezervaci na novou účtenku</a></p> | |
{else} | |
<div class="row reservation-bill-list"> | |
{foreach $bills as $bill} | |
<div class="col-xs-3"> | |
<a href="{link showReservationFormForBill!, billId => $bill->getId()}" class="ajax bill-item">{$bill->getName()}</a> | |
</div> | |
{/foreach} | |
</div> | |
{/if} | |
{elseif $intoNewBill === true} | |
{include #back} | |
{control reservationIntoNewBill} | |
{else} | |
{include #typeSelection} | |
{/if} | |
{/if} | |
{/if} | |
{define back} | |
<a href="{link back!}" class="ajax">zpět</a> | |
{/define} | |
{define typeSelection} | |
<div class="row reservation-type-selection"> | |
<div class="col-xs-6"> | |
<a href="{link intoNewBill!}" class="ajax btn btn-default">{if $reservation === null}Rezervace na novou účtenku{else}Přidat účastníky na novou účtenku{/if}</a> | |
</div> | |
<div class="col-xs-6"> | |
<a href="{link intoExistingBill!}" class="ajax btn btn-default">{if $reservation === null}Rezervace na otevřenou účtenku{else}Upravit počet účastníků na otevřené účtence{/if}</a> | |
</div> | |
</div> | |
{/define} | |
{define reservationTypeSelection} | |
<div class="reservation-type-selection text-center"> | |
<a href="{link showReservationForm!}" class="ajax btn btn-default">Rezervace</a> | |
<a href="{link ShowRepeatableReservationForm!}" class="ajax btn btn-default">Opakovaná rezervace</a> | |
</div> | |
{/define} | |
{/snippet} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Reservations\Components; | |
use CreativeProjects\Components\FlashMessages\FlashMessage; | |
use CreativeProjects\Components\BaseControl; | |
use Reservations\Facades\ReservationFacade; | |
use Reservations\Queries\ReservationQuery; | |
use Reservations\Traits\THoursCalculation; | |
use Reservations\SportsField; | |
use Reservations\Reservation; | |
use Sales\Facades\BillFacade; | |
use Sales\Queries\BillQuery; | |
use Sales\ReservationItem; | |
use Sales\Bill; | |
class SportsFieldReservationControl extends BaseControl | |
{ | |
use THoursCalculation; | |
public $onSuccessfulReservationCreation; | |
public $onParticipantResetting; | |
public $onMissingSportsField; | |
/** @persistent */ | |
public $billSelection = true; | |
/** @persistent */ | |
public $intoNewBill = false; | |
/** @persistent */ | |
public $intoExistingBill = false; | |
/** @persistent */ | |
public $chosenBillId; | |
/** @persistent */ | |
public $repeatableReservation = false; | |
/** @persistent */ | |
public $singleReservation = false; | |
/** @var IRepeatableReservationFormControlFactory */ | |
private $repeatableReservationFormControlFactory; | |
/** @var IReservationIntoNewBillControlFactory */ | |
private $reservationIntoNewBillControlFactory; | |
/** @var IReservationFormControlFactory */ | |
private $reservationFormControlFactory; | |
/** @var ISportsFieldControlFactory */ | |
private $sportsFieldControlFactory; | |
/** @var ReservationFacade */ | |
private $reservationFacade; | |
/** @var Reservation */ | |
private $reservation; | |
/** @var SportsField|null */ | |
private $sportsField; | |
/** @var BillFacade */ | |
private $billFacade; | |
/** @var Bill[] */ | |
private $bills; | |
/** @var Bill */ | |
private $bill; | |
/** @var \DateTimeImmutable */ | |
private $day; | |
/** @var \DateTimeImmutable */ | |
private $clickedHour; | |
public function __construct( | |
\DateTimeImmutable $day, | |
SportsField $sportsField = null, | |
BillFacade $billFacade, | |
ReservationFacade $reservationFacade, | |
ISportsFieldControlFactory $sportsFieldControlFactory, | |
IReservationFormControlFactory $reservationFormControlFactory, | |
IReservationIntoNewBillControlFactory $reservationIntoNewBillControlFactory, | |
IRepeatableReservationFormControlFactory $repeatableReservationFormControlFactory | |
) { | |
$this->day = $day; | |
$this->billFacade = $billFacade; | |
$this->sportsField = $sportsField; | |
$this->reservationFacade = $reservationFacade; | |
$this->sportsFieldControlFactory = $sportsFieldControlFactory; | |
$this->reservationFormControlFactory = $reservationFormControlFactory; | |
$this->reservationIntoNewBillControlFactory = $reservationIntoNewBillControlFactory; | |
$this->repeatableReservationFormControlFactory = $repeatableReservationFormControlFactory; | |
} | |
/** | |
* @param Reservation $reservation | |
*/ | |
public function setReservation(Reservation $reservation) | |
{ | |
$this->reservation = $reservation; | |
} | |
/** | |
* @param string $clickedHour e.g "12:00" | |
*/ | |
public function setClickedHour($clickedHour) | |
{ | |
$this->clickedHour = \DateTimeImmutable::createFromFormat('Y-m-d H:i', sprintf('%s %s', $this->day->format('Y-m-d'), $clickedHour)); | |
} | |
public function render() | |
{ | |
$template = $this->getTemplate(); | |
$template->setFile(__DIR__ . '/sportsFieldReservation.latte'); | |
$template->sportsField = $this->sportsField; | |
$template->reservation = $this->reservation; | |
$template->day = $this->day; | |
$template->currentDate = \DateTimeImmutable::createFromFormat('!Y-n-j', date('Y-n-j')); | |
$template->chosenBillId = $this->chosenBillId; | |
$template->billSelection = (bool)$this->billSelection; | |
$template->intoNewBill = (bool)$this->intoNewBill; | |
$template->singleReservation = (bool)$this->singleReservation; | |
$template->repeatableReservation = (bool)$this->repeatableReservation; | |
if ($this->sportsField !== null and $this->intoExistingBill == true and $this->bills === null) { | |
$this->bills = $this->findOpenedBills(); | |
} | |
$template->bills = $this->bills; | |
if ($this->sportsField !== null and $this->bill === null) { | |
if ($this->chosenBillId !== null) { | |
$this->bill = $this->billFacade->getBillById($this->chosenBillId); | |
} | |
} | |
$template->bill = $this->bill; | |
$template->render(); | |
} | |
public function handleShowReservationForm() | |
{ | |
$this->singleReservation = true; | |
$this->repeatableReservation = false; | |
if ($this->sportsField === null) { | |
$this->resetState(); | |
$this->onMissingSportsField($this); | |
} | |
$this->refresh('this', ['selection']); | |
} | |
public function handleShowRepeatableReservationForm() | |
{ | |
$this->singleReservation = false; | |
$this->repeatableReservation = true; | |
if ($this->sportsField === null) { | |
$this->resetState(); | |
$this->onMissingSportsField($this); | |
} | |
$this->refresh('this', ['selection']); | |
} | |
protected function createComponentReservationForm() | |
{ | |
if ($this->bill === null) { | |
$this->bill = $this->billFacade->getBillById($this->chosenBillId); | |
} | |
$comp = $this->reservationFormControlFactory | |
->create( | |
$this->day, | |
$this->bill, | |
$this->sportsField | |
); | |
if ($this->reservation !== null) { | |
$comp->setReservation($this->reservation); | |
} | |
if ($this->clickedHour !== null) { | |
$defaultTimes = $this->findFreeReservationDefaultTimes($this->clickedHour); | |
$comp->setDefaultTimes($defaultTimes['start'], $defaultTimes['end']); | |
} | |
$comp->onSuccessfulReservation[] = [$this, 'onSuccessfulReservation']; | |
$comp->onMissingSportsField[] = function (ReservationFormControl $control) { | |
$this->resetState(); | |
$this->onMissingSportsField($this); | |
}; | |
return $comp; | |
} | |
public function onSuccessfulReservation(ReservationFormControl $control, ReservationItem $reservationItem) | |
{ | |
$this->resetState(); | |
$this->flashMessage('Rezervace byla úspěšně uložena', FlashMessage::SUCCESS); | |
$this->onSuccessfulReservationCreation($this, $this->sportsField); | |
$this->refresh('this'); | |
} | |
/** | |
* @param \DateTimeImmutable $clickedHour | |
* @return \DateTimeImmutable | |
*/ | |
private function findFreeReservationDefaultTimes(\DateTimeImmutable $clickedHour) | |
{ | |
$clickedHourStartTime = \DateTimeImmutable::createFromFormat('Y-m-d H:i', sprintf('%s %s', $this->day->format('Y-m-d'), $clickedHour->format('H:i'))); | |
$clickedHourEndTime = $clickedHourStartTime->modify('+ 1 hour'); | |
$reservations = $this->reservationFacade | |
->findReservationsInPeriod($clickedHourStartTime, $clickedHourEndTime, $this->sportsField); | |
if (empty($reservations)){ // žádné rezervace, celá vybraná hodina je dostupná | |
return ['start' => $clickedHourStartTime, 'end' => $clickedHourEndTime, 'state' => 'ok']; | |
} | |
$reservationsCount = count($reservations); | |
// V jeden čas může být aktivní pouze jedna rezervace. | |
// Pokud tedy z databáze dostaneme více než jednu rezervaci, není možné, | |
// aby některá z rezervací pokrývala celý vybraný čas z tabulky rezervací | |
// Může nastat situace, kdy prodejce vidí volnou hodinu a bude chtít | |
// vytvořit rezervaci, ale průběhu vybírání účtenky apod. než se dostane k | |
// formuláři, do kterého se generují defaultní hodnoty času podle existujících | |
// rezervací, z online databáze se přes synchronizaci vytvoří rezervace a nebude | |
// tak možné vytvořit rezervaci na lokalhostu. Zde dochází k problému nastavení | |
// konečného defaultního času, který je popsán v komentářích níže. | |
// Rezervace jsou seřazeny již z databáze | |
/** @var Reservation $firstReservation */ | |
$firstReservation = array_shift($reservations); | |
// začátek a konec největšího volného času mezi rezervacemi | |
$highestFreeTimeStart = null; | |
$highestFreeTimeEnd = null; | |
if ($firstReservation->getStart() < $clickedHourStartTime) { | |
// todo => mohou nastat 2 situace, první je OK a druhá potřebuje vyřešit | |
// 1. rezervace končí dřív než končí vybraná hodina ($reservation->getEnd() < $clickedHourEndTime) | |
// -> OK, mezi koncem rezervace a koncem vybrané hodiny je "nějaký" volný čas | |
if ($firstReservation->getEnd() < $clickedHourEndTime) { // ve vybrané hodině se může nacházet 1 nebo více rezervací | |
$highestFreeTimeStart = $firstReservation->getEnd(); | |
if ($reservationsCount === 1) { | |
// pokud se ve vybrané hodině nachází pouze jedna rezervace, můžeme určit i konečný defaultní čas | |
$highestFreeTimeEnd = $clickedHourEndTime; | |
} | |
} else { // ve vybrané hodině nachází pouze jedna rezervace, protože zabírá celou vybranou hodinu | |
// 2. konec rezervace přesahuje konec vybrané hodiny ($reservation->getEnd() >= $clickedHourEndTime) | |
// -> problém, ve vybrané hodině není žádný volný čas. | |
// *** JAKÝ NASTAVIT DEFAULTNÍ KONEČNÝ ČAS V TOMTO PŘÍPADĚ? *** | |
// todo jaké nastavit defaultní hodnoty? | |
// rezervace začíná před počátkem vybrané hodiny a končí až za koncem vybrané hodiny, | |
// takže nelze stanovit defaultní počáteční čas | |
$highestFreeTimeStart = $clickedHourStartTime; | |
// Druhý případ vyřešen tak, že se prostě nastaví konečný čas vybrané hodiny | |
// a po zpracování rezervace se zobrazí hláška, že termín není volný. | |
// Po uzavření modálního okna prodejce uvidí, že již není termín volný | |
$highestFreeTimeEnd = $clickedHourEndTime; | |
} | |
} else { // >= rezervace začíná ve stejný čas jako vybraná hodina nebo později. | |
// nastavíme jako výchozí počáteční čas začátek vybrané hodiny z | |
// tabulky rezervací, protože první rezervace zasahující do vybraného času | |
// může začínat ve stejný čas jako čas vybraný nebo později. Proto | |
// bude výchozí čas začínat počátkem vybraného času z tabulky rezervací. | |
//$highestFreeTimeStart = $clickedHourStartTime; | |
//$highestFreeTimeEnd = $firstReservation->getStart(); // může být shodný se začátkem vybrané hodiny | |
// Pokud rezervace nezačíná ve stejný čas jako vybraná hodina, existuje nějaký volný čas | |
if ($firstReservation->getStart() != $clickedHourStartTime) { | |
$highestFreeTimeStart = $clickedHourStartTime; | |
$highestFreeTimeEnd = $firstReservation->getStart(); | |
} else { // == rezervace začíná ve stejný čas jako vybraná hodina | |
if ($firstReservation->getEnd() < $clickedHourEndTime) { // ve vybrané hodině se může nacházet více rezervací | |
$highestFreeTimeStart = $firstReservation->getEnd(); | |
if ($reservationsCount === 1) { | |
// pokud se ve vybrané hodině nachází pouze jedna rezervace, můžeme určit i konečný defaultní čas | |
$highestFreeTimeEnd = $clickedHourEndTime; | |
} | |
} else { // >= ve vybrané hodině se nachází pouze jedna rezervace a ta zabírá celkový čas | |
// todo jaké nastavit defaultní hodnoty? | |
$highestFreeTimeStart = $clickedHourStartTime; | |
$highestFreeTimeEnd = $clickedHourEndTime; | |
} | |
} | |
} | |
// konec rezervace procházené naposled | |
$lastReservationEndTime = $firstReservation->getEnd(); | |
$highestFreeTimePeriod = null; | |
/** @var Reservation $reservation */ | |
foreach ($reservations as $reservation) { | |
if ($highestFreeTimeEnd === null) { | |
$highestFreeTimeEnd = $reservation->getStart(); | |
} | |
$highestFreeTimePeriod = $highestFreeTimeEnd->diff($highestFreeTimeStart); | |
$currentFreeTimePeriod = $reservation->getStart()->diff($lastReservationEndTime); | |
$highestFreeTimePeriodInMinutes = ($highestFreeTimePeriod->h * 60) + $highestFreeTimePeriod->i; | |
$currentFreeTimePeriodInMinutes = ($currentFreeTimePeriod->h * 60) + $currentFreeTimePeriod->i; | |
if ($currentFreeTimePeriodInMinutes > $highestFreeTimePeriodInMinutes) { | |
$highestFreeTimeStart = $lastReservationEndTime; | |
$highestFreeTimeEnd = $reservation->getStart(); | |
} | |
$lastReservationEndTime = $reservation->getEnd(); | |
} | |
return ['start' => $highestFreeTimeStart, 'end' => $highestFreeTimeEnd, 'state' => 'ok']; | |
} | |
protected function createComponentRepeatableReservationForm() | |
{ | |
if ($this->bill === null) { | |
$this->bill = $this->billFacade->getBillById($this->chosenBillId); | |
} | |
$comp = $this->repeatableReservationFormControlFactory | |
->create( | |
$this->bill, | |
$this->day, | |
$this->sportsField | |
); | |
$comp->onSuccessfulRepeatableReservation[] = [$this, 'onSuccessfulRepeatableReservation']; | |
return $comp; | |
} | |
public function onSuccessfulRepeatableReservation(RepeatableReservationFormControl $control) | |
{ | |
$this->resetState(); | |
$this->flashMessage('Rezervace byli úspěšně uloženy', FlashMessage::SUCCESS); | |
$this->onSuccessfulReservationCreation($this); | |
$this->refresh('this'); | |
} | |
protected function createComponentSportsFieldReservations() | |
{ | |
$comp = $this->sportsFieldControlFactory | |
->create($this->day, $this->sportsField); | |
$reservations = $this->findReservations($this->sportsField); | |
foreach ($reservations as $reservation) { | |
$comp->addReservation($reservation); | |
} | |
return $comp; | |
} | |
public function handleShowReservationFormForBill($billId) | |
{ | |
$this->resetState(); | |
$this->billSelection = false; | |
$this->chosenBillId = $billId; | |
$this->bill = $this->billFacade->getBillById($this->chosenBillId); | |
if ($this->reservation !== null) { | |
$this->singleReservation = true; | |
} | |
if ($this->sportsField === null) { | |
$this->resetState(); | |
$this->onMissingSportsField($this); | |
} | |
$this->refresh('this', ['selection']); | |
} | |
public function handleIntoNewBill() | |
{ | |
$this->resetState(); | |
$this->billSelection = false; | |
$this->intoNewBill = true; | |
if ($this->sportsField === null) { | |
$this->resetState(); | |
$this->onMissingSportsField($this); | |
} | |
$this->refresh('this', ['selection']); | |
} | |
public function handleIntoExistingBill() | |
{ | |
$this->resetState(); | |
$this->billSelection = false; | |
$this->intoExistingBill = true; | |
if ($this->sportsField === null) { | |
$this->resetState(); | |
$this->onMissingSportsField($this); | |
} | |
$this->refresh('this', ['selection']); | |
} | |
public function handleBack() | |
{ | |
$this->resetState(); | |
$this->refresh('this', ['selection']); | |
} | |
public function handleNewReservation() | |
{ | |
$this->resetState(); | |
$this->reservation = null; | |
$this->onParticipantResetting($this); | |
} | |
protected function createComponentReservationIntoNewBill() | |
{ | |
$comp = $this->reservationIntoNewBillControlFactory | |
->create($this->day, $this->sportsField); | |
$comp->onSuccessfulBillSaving[] = [$this, 'onSuccessfulBillSaving']; | |
return $comp; | |
} | |
public function onSuccessfulBillSaving(ReservationIntoNewBillControl $control, Bill $bill) | |
{ | |
$this->resetState(); | |
$this->billSelection = false; | |
$this->chosenBillId = $bill->getId(); | |
$this->refresh('this', ['selection']); | |
} | |
/** | |
* @param SportsField $sportsField | |
* @return Reservation[] | |
*/ | |
private function findReservations(SportsField $sportsField) | |
{ | |
$start = \DateTimeImmutable::createFromFormat('!Y-m-d H:i:s', $this->day->format('Y-m-d H:i:s')); | |
$end = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $this->day->modify('tomorrow')->format('Y-m-d H:i:s')); | |
return $this->reservationFacade | |
->findReservations( | |
(new ReservationQuery()) | |
->byReservationTime($start, $end, $sportsField) | |
)->toArray(); | |
} | |
/** | |
* @return Bill[] | |
*/ | |
private function findOpenedBills() | |
{ | |
return $this->billFacade | |
->findBills( | |
(new BillQuery()) | |
->onlyOpened() | |
)->toArray(); | |
} | |
private function resetState() | |
{ | |
$this->chosenBillId = null; | |
$this->intoNewBill = false; | |
$this->intoExistingBill = false; | |
$this->billSelection = true; | |
$this->singleReservation = false; | |
$this->repeatableReservation = false; | |
} | |
} | |
interface ISportsFieldReservationControlFactory | |
{ | |
/** | |
* @param \DateTimeImmutable $day | |
* @param SportsField|null $sportsField | |
* @return SportsFieldReservationControl | |
*/ | |
public function create(\DateTimeImmutable $day, SportsField $sportsField = null); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{snippet row} | |
{if $sportsField !== null} | |
<div style="overflow: auto; clear: both;"> | |
<div style="width: 10%;" class="td title"> | |
{$sportsField->getName()|truncate:10} | |
</div> | |
<div style="position: relative; float: left; width: 90%;"> | |
{if $isSportsFieldOpened === true} | |
{var $columnCounter = 0} | |
{for $i = 0; $i < $numberOfColumns; $i++} | |
<div style="width:{!$columnLength}%;" class="td"> | |
{if $i >= $startColumn and $i < $endColumn} | |
<a href="#" data-modal="reservation_form" data-url="{link showDetail, columnNumber => $columnCounter}" class="modal-opener"> | |
<i class="fa fa-clock-o"></i> | |
</a> | |
{php $columnCounter++} | |
{/if} | |
</div> | |
{/for} | |
{else} | |
<div style="width: 100%;" class="td empty"> | |
Sportoviště je v tento den uzavřeno | |
</div> | |
{/if} | |
{* reservations *} | |
{snippet reservations} | |
{if count($reservations)} | |
{foreach $reservations as $reservation} | |
{var $reservationID = $reservation->getId()} | |
{control reservation-$reservationID} | |
{/foreach} | |
{/if} | |
{/snippet} | |
</div> | |
</div> | |
{/if} | |
{/snippet} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Reservations\Components; | |
use CreativeProjects\Components\BaseControl; | |
use Nette\Application\UI\Multiplier; | |
use Reservations\Reservation; | |
use Reservations\SportsField; | |
class SportsFieldRowControl extends BaseControl | |
{ | |
public $onEditReservation; | |
public $onNewReservation; | |
/** @var IReservationControlFactory */ | |
private $reservationControlFactory; | |
/** @var int */ | |
private $numberOfColumnsToDisplay; | |
/** @var Reservation[] */ | |
private $reservations; | |
/** @var SportsField|null */ | |
private $sportsField; | |
/** @var \DateTimeInterface */ | |
private $startTime; | |
/** @var \DateTimeInterface */ | |
private $endTime; | |
/** @var \DateTimeInterface */ | |
private $day; | |
public function __construct( | |
\DateTimeInterface $day, | |
$numberOfColumnsToDisplay, | |
SportsField $sportsField = null, | |
IReservationControlFactory $reservationControlFactory | |
) { | |
$this->day = $day; | |
$this->sportsField = $sportsField; | |
$this->numberOfColumnsToDisplay = $numberOfColumnsToDisplay; | |
$this->reservationControlFactory = $reservationControlFactory; | |
} | |
public function render() | |
{ | |
$template = $this->getTemplate(); | |
$template->setFile(__DIR__ . '/sportsFieldRow.latte'); | |
$template->sportsField = $this->sportsField; | |
$template->reservations = $this->reservations; | |
if ($this->sportsField !== null and (!isset($this->startTime) or !isset($this->endTime))) { | |
$this->startTime = $this->sportsField->getOpeningTime($this->day->format('D')); | |
$this->endTime = $this->sportsField->getClosingTime($this->day->format('D')); | |
} | |
$template->numberOfColumns = $this->numberOfColumnsToDisplay; | |
$template->columnLength = 100 / $this->numberOfColumnsToDisplay; | |
$startColumn = 1; | |
$endColumn = $this->numberOfColumnsToDisplay; | |
$isSportsFieldOpened = true; | |
if ($this->sportsField !== null and $this->sportsField->isOpenedInWeekDay($this->day)) { | |
$sportsFieldOpeningTime = $this->sportsField->getOpeningTime($this->day->format('D')); | |
$sportsFieldClosingTime = $this->sportsField->getClosingTime($this->day->format('D')); | |
$openingTime = \DateTimeImmutable::createFromFormat('!H', $sportsFieldOpeningTime->format('H')); | |
$closingTime = \DateTimeImmutable::createFromFormat('!H', $sportsFieldClosingTime->modify('next hour')->format('H')); | |
$startColumn = $openingTime->diff($this->startTime)->h; | |
$endColumn = $this->numberOfColumnsToDisplay - $closingTime->diff($this->endTime)->h; | |
} else { | |
$isSportsFieldOpened = false; | |
} | |
$template->startColumn = $startColumn; | |
$template->endColumn = $endColumn; | |
$template->isSportsFieldOpened = $isSportsFieldOpened; | |
$template->render(); | |
} | |
protected function createComponentReservation() | |
{ | |
return new Multiplier(function ($reservationId) { | |
$comp = $this->reservationControlFactory | |
->create( | |
$this->reservations[$reservationId], | |
$this->startTime, | |
$this->endTime | |
); | |
$comp->onModal[] = [$this, 'onReservationDetail']; | |
return $comp; | |
}); | |
} | |
public function onReservationDetail(ReservationControl $control, Reservation $reservation) | |
{ | |
$this->onEditReservation($this, $reservation); | |
} | |
public function handleShowDetail($columnNumber) | |
{ | |
$globalStartTime = clone $this->startTime; | |
$clickedHour = $globalStartTime->modify(sprintf('+ %s hour%s', $columnNumber, $columnNumber < 2 ? null : 's')); | |
if ($this->sportsField === null) { | |
$this->redrawControl('row'); | |
} | |
$this->onNewReservation($this, $clickedHour); | |
} | |
/** | |
* @param Reservation $reservation | |
*/ | |
public function addReservation(Reservation $reservation) | |
{ | |
if ($this->sportsField->getId() == $reservation->getSportsFieldId()) { | |
$this->reservations[$reservation->getId()] = $reservation; | |
} | |
} | |
/** | |
* @param \DateTimeInterface $startTime | |
* @param \DateTimeInterface $endTime | |
*/ | |
public function setGlobalOuterTimes(\DateTimeInterface $startTime, \DateTimeInterface $endTime) | |
{ | |
$this->startTime = $startTime; | |
$this->endTime = $endTime; | |
} | |
} | |
interface ISportsFieldRowControlFactory | |
{ | |
/** | |
* @param \DateTimeInterface $day, | |
* @param int $numberOfColumnsToDisplay | |
* @param SportsField|null $sportsField | |
* @return SportsFieldRowControl | |
*/ | |
public function create(\DateTimeInterface $day, $numberOfColumnsToDisplay, SportsField $sportsField = null); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="reservations" id="table-of-reservations" data-url="{link refreshTable}" data-automatically-refresh-table="{$automaticallyRefreshReservationTable}" data-refresh-rate="{$reservationTableRefreshRate}"> | |
{snippet reservationsTable} | |
<div class="header"> | |
<div style="width: 10%;" class="th corner"> </div> | |
<div style="position: relative; float: left; width: 90%;"> | |
<div style="width:{!$columnLength}%;" class="th" n:for="$i = 0; $i < $numberOfColumns; $i++"> | |
{$startTime->modify(sprintf('+%s hour', $i))|date:'H:i'} | |
</div> | |
</div> | |
</div> | |
<div class="body"> | |
{if count($sportsFields) > 0} | |
{foreach $sportsFields as $sportsField} | |
{var $sportsFieldId = $sportsField->getId()} | |
{control sportsFieldRow-$sportsFieldId} | |
{/foreach} | |
{else} | |
Žádná sportoviště k zobrazení | |
{/if} | |
</div> | |
{/snippet} | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Reservations\Components; | |
use CreativeProjects\Components\BaseControl; | |
use Reservations\Facades\ReservationFacade; | |
use Reservations\Facades\SportsFieldFacade; | |
use Reservations\Queries\ReservationQuery; | |
use Reservations\Traits\THoursCalculation; | |
use Nette\Application\UI\Multiplier; | |
use Reservations\Reservation; | |
use Reservations\SportsField; | |
class SportsFieldsOverviewControl extends BaseControl | |
{ | |
use THoursCalculation; | |
public $onFreeTimeClick; | |
public $onReservedTimeClick; | |
/** @var ISportsFieldReservationControlFactory */ | |
private $sportsFieldReservationControlFactory; | |
/** @var IReservationFormControlFactory */ | |
private $reservationFormControlFactory; | |
/** @var ISportsFieldRowControlFactory */ | |
private $sportsFieldRowControlFactory; | |
/** @var ISportsFieldControlFactory */ | |
private $sportsFieldControlFactory; | |
/** @var SportsFieldFacade */ | |
private $sportsFieldFacade; | |
/** @var ReservationFacade */ | |
private $reservationFacade; | |
/** @var SportsField[] */ | |
private $sportsFields; | |
/** @var Reservation[] */ | |
private $reservations; | |
/** @var Reservation */ | |
private $reservation; | |
/** @var \DateTimeInterface */ | |
private $date; | |
/** @var int */ | |
private $numberOfColumnsToDisplay; | |
/** @var \DateTimeInterface */ | |
private $startTime; | |
/** @var \DateTimeInterface */ | |
private $endTime; | |
private $automaticallyRefreshReservationTable = true; | |
private $reservationTableRefreshRate = 35000; // in ms (35000ms => 35s) | |
public function __construct( | |
\DateTimeInterface $date, | |
array $sportsFields, | |
SportsFieldFacade $sportsFieldFacade, | |
ReservationFacade $reservationFacade, | |
ISportsFieldControlFactory $sportsFieldControlFactory, | |
ISportsFieldRowControlFactory $sportsFieldRowControlFactory, | |
IReservationFormControlFactory $reservationFormControlFactory, | |
ISportsFieldReservationControlFactory $sportsFieldReservationControlFactory | |
) { | |
$this->date = $date; | |
$this->sportsFields = $sportsFields; | |
$this->sportsFieldFacade = $sportsFieldFacade; | |
$this->reservationFacade = $reservationFacade; | |
$this->sportsFieldControlFactory = $sportsFieldControlFactory; | |
$this->sportsFieldRowControlFactory = $sportsFieldRowControlFactory; | |
$this->reservationFormControlFactory = $reservationFormControlFactory; | |
$this->sportsFieldReservationControlFactory = $sportsFieldReservationControlFactory; | |
} | |
public function setSportsFields(array $sportsFields) | |
{ | |
$this->sportsFields = $sportsFields; | |
} | |
public function doNotRefreshTable() | |
{ | |
$this->automaticallyRefreshReservationTable = false; | |
} | |
/** | |
* @param int $refreshRate in milliseconds | |
*/ | |
public function setTableRefreshRate($refreshRate) | |
{ | |
$this->reservationTableRefreshRate = $refreshRate; | |
} | |
public function render() | |
{ | |
$template = $this->getTemplate(); | |
$template->setFile(__DIR__ . '/sportsFieldsOverview.latte'); | |
$sportsFieldCount = count($this->sportsFields); | |
if ($sportsFieldCount === 1) { | |
$this->findReservations(reset($this->sportsFields)); | |
} elseif ($sportsFieldCount > 1) { | |
$this->findReservations(); | |
} | |
$template->sportsFields = $this->sportsFields; | |
$template->displayedDate = $this->date; | |
$template->currentDate = \DateTimeImmutable::createFromFormat('!Y-n-j', date('Y-n-j')); | |
// ----- | |
if (!isset($this->startTime) or !isset($this->endTime)) { | |
$outerDateTimes = $this->findOuterDateTimes($this->date, $this->sportsFields, $this->reservations); | |
$startTime = $outerDateTimes['openingTime']; | |
$endTime = $outerDateTimes['closingTime']; | |
$numberOfHours = $this->calcNumberOfHours($startTime, $endTime); | |
$this->startTime = $startTime; | |
$this->endTime = $endTime; | |
$this->numberOfColumnsToDisplay = $numberOfHours; | |
} | |
$template->startTime = $this->startTime; | |
$template->numberOfColumns = $this->numberOfColumnsToDisplay; | |
$template->columnLength = 100 / $this->numberOfColumnsToDisplay; | |
$this->template->reservationTableRefreshRate = $this->reservationTableRefreshRate; | |
$this->template->automaticallyRefreshReservationTable = (int)$this->automaticallyRefreshReservationTable; | |
$template->render(); | |
} | |
protected function createComponentSportsFieldRow() | |
{ | |
return new Multiplier(function ($sportsFieldId) { | |
$sportsField = null; | |
if (empty($this->sportsFields)) { // ajax | |
$sportsField = $this->sportsFieldFacade->getSportsFieldById($sportsFieldId); | |
$this->sportsFields = []; | |
if ($sportsField !== null) { | |
$this->sportsFields[$sportsFieldId] = $sportsField; | |
$this->findReservations($sportsField); | |
} | |
} else { | |
if (isset($this->sportsFields[$sportsFieldId])) { | |
if ($this->sportsFields[$sportsFieldId]->isFrozen() !== true) { | |
$sportsField = $this->sportsFields[$sportsFieldId]; | |
} | |
} | |
} | |
if (!isset($this->startTime) or !isset($this->endTime)) { | |
$outerDateTimes = $this->findOuterDateTimes($this->date, $this->sportsFields, $this->reservations); | |
$this->startTime = $outerDateTimes['openingTime']; | |
$this->endTime = $outerDateTimes['closingTime']; | |
$this->numberOfColumnsToDisplay = $this->calcNumberOfHours($this->startTime, $this->endTime); | |
} | |
$comp = $this->sportsFieldRowControlFactory | |
->create($this->date, $this->numberOfColumnsToDisplay, $sportsField); | |
$comp->setGlobalOuterTimes($this->startTime, $this->endTime); | |
$comp->onNewReservation[] = function (SportsFieldRowControl $control, \DateTimeImmutable $clickedHour) use ($sportsField) { | |
$this->onFreeTimeClick($this, $control, $sportsField, $clickedHour); | |
}; | |
$comp->onEditReservation[] = function (SportsFieldRowControl $control, Reservation $reservation) use ($sportsFieldId) { | |
$this->onReservedTimeClick($this, $control, $this->sportsFields[$sportsFieldId], $reservation); | |
}; | |
if (!empty($this->reservations)) { | |
foreach ($this->reservations as $reservation) { | |
$comp->addReservation($reservation); | |
} | |
} | |
return $comp; | |
}); | |
} | |
/*protected function createComponentSportsFieldReservation() | |
{ | |
if ($this->selectedSportsField === null) { | |
$this->selectedSportsField = $this->sportsFieldFacade | |
->getSportsFieldById($this->selectedSportsFieldId); | |
if ($this->selectedSportsField->isFrozen() or $this->selectedSportsField === null) { | |
throw new SportsFieldNotFoundException; // todo | |
} | |
} | |
$comp = $this->sportsFieldReservationControlFactory | |
->create($this->date, $this->selectedSportsField); | |
if ($this->clickedHour !== null) { | |
$comp->setClickedHour($this->clickedHour); | |
} | |
if ($this->reservationId !== null) { | |
if ($this->reservation === null) { | |
$this->reservation = $this->reservationFacade->getReservationById($this->reservationId); | |
} | |
$comp->setReservation($this->reservation); | |
} | |
$comp->onSuccessfulReservationCreation[] = function () { | |
$this->sportsFields = null; | |
$this->reservations = null; | |
$this['sportsFieldRow'][$this->selectedSportsField->getId()]->redrawControl(); | |
}; | |
return $comp; | |
}*/ | |
/** | |
* @param SportsField|null $sportsField | |
*/ | |
private function findReservations(SportsField $sportsField = null) | |
{ | |
if ($this->reservations !== null) { | |
return; | |
} | |
$start = \DateTimeImmutable::createFromFormat('!Y-m-d H:i:s', $this->date->format('Y-m-d H:i:s')); | |
$end = \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $this->date->modify('tomorrow')->format('Y-m-d H:i:s')); | |
$this->reservations = $this->reservationFacade | |
->findReservations( | |
(new ReservationQuery()) | |
->byReservationTime($start, $end, $sportsField) | |
)->toArray(); | |
} | |
/** | |
* @param \DateTimeInterface $date | |
* @param array $sportsFields | |
* @param array $reservations | |
* @return array [openingTime => \DateTimeImmutable, closingTime => \DateTimeImmutable] | |
*/ | |
private function findOuterDateTimes(\DateTimeInterface $date, array $sportsFields, array $reservations = null) | |
{ | |
$defaultOpeningTime = \DateTimeImmutable::createFromFormat('!H:i', '08:00'); | |
$defaultClosingTime = \DateTimeImmutable::createFromFormat('!H:i', '16:00'); | |
if (empty($sportsFields)) { | |
return [ | |
'openingTime' => $defaultOpeningTime, | |
'closingTime' => $defaultClosingTime | |
]; | |
} | |
$weekDay = $date->format('D'); | |
/** @var SportsField $sf */ | |
$sf = array_shift($sportsFields); | |
$openingTime = $sf->getOpeningTime($weekDay); | |
if ($openingTime === null) { | |
$openingTime = $defaultOpeningTime; | |
} | |
$closingTime = $sf->getClosingTime($weekDay); | |
if ($closingTime === null) { | |
$closingTime = $defaultClosingTime; | |
} | |
/** @var SportsField $sportsField */ | |
foreach ($sportsFields as $sportsField) { | |
if (!$sportsField->isOpenedInWeekDay($weekDay)) { | |
continue; | |
} | |
$sot = $sportsField->getOpeningTime($weekDay); | |
if ($sot < $openingTime) { | |
$openingTime = $sot; | |
} | |
$sct = $sportsField->getClosingTime($weekDay); | |
if ($sct > $closingTime) { | |
$closingTime = $sct; | |
} | |
} | |
if (!empty($reservations)) { | |
/** @var Reservation $reservation */ | |
foreach ($reservations as $reservation) { | |
$rs = \DateTimeImmutable::createFromFormat('!H:i:s', $reservation->getStart('H:i:s')); | |
if ($rs < $openingTime) { | |
$openingTime = $rs; | |
} | |
$re = \DateTimeImmutable::createFromFormat('!H:i:s', $reservation->getEnd('H:i:s')); | |
if ($re > $closingTime) { | |
$closingTime = $re; | |
} | |
} | |
} | |
$startTime = \DateTimeImmutable::createFromFormat('!d.m.Y H', $openingTime->format('d.m.Y H')); | |
$endTime = \DateTimeImmutable::createFromFormat('!d.m.Y H', $closingTime->modify('next hour')->format('d.m.Y H')); | |
return ['openingTime' => $startTime, 'closingTime' => $endTime]; | |
} | |
public function handleRefreshTable() | |
{ | |
if ($this->presenter->isAjax()) { | |
$this->redrawControl('reservationsTable'); | |
} else { | |
//$this->redirect('this'); // todo redirect? | |
} | |
} | |
} | |
interface ISportsFieldsOverviewControlFactory | |
{ | |
/** | |
* @param \DateTimeInterface $date | |
* @param array $sportsFields | |
* @return SportsFieldsOverviewControl | |
*/ | |
public function create(\DateTimeInterface $date, array $sportsFields); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment