class MerciDefaultController_non_inventory in MERCI (Manage Equipment Reservations, Checkout and Inventory) 7.3
A null implementation of EntityReference_SelectionHandler.
Hierarchy
Expanded class hierarchy of MerciDefaultController_non_inventory
File
- merci_core/
reservation.handler.inc, line 418 - Abstraction of the selection logic of an entity reference field.
View source
class MerciDefaultController_non_inventory extends MerciDefaultController {
protected $date_column, $date_column2;
protected $buckets;
protected function validate() {
if (!$this->validated) {
$this->buckets = $this
->fillBuckets();
$this->validated = TRUE;
$conflicts = array();
foreach ($this->buckets as $delta => $dates) {
foreach ($dates as $date_value => $buckets) {
if (!isset($this->quantity_reserved[$delta])) {
$this->quantity_reserved[$delta] = array();
}
$this->quantity_reserved[$delta][$date_value] = count($buckets);
if (!isset($conflicts[$delta])) {
$conflicts[$delta] = array();
}
$conflicts[$delta][$date_value] = array();
foreach ($buckets as $bucket) {
$conflicts[$delta][$date_value] = array_merge($conflicts[$delta][$date_value], $bucket);
}
}
}
$this->conflicting_entities = $conflicts;
}
}
public function fillBuckets() {
$conflicts = array();
foreach ($this->dates as $dates) {
$date_value = $dates['value'];
$result = $this
->bestFit($dates);
// Result is array indexed by $delta of filled buckets.
foreach ($result as $delta => $buckets) {
if (!isset($conflicts[$delta])) {
$conflicts[$delta] = array();
}
$conflicts[$delta][$date_value] = $buckets;
}
}
return $conflicts;
}
public function reservations($dates, $exclude_id) {
$bestfit = $this
->bestFit($dates);
$reservations = array();
foreach ($bestfit as $enity_id => $reservation) {
$reservations[] = $entity_id;
}
return $reservations;
}
/*
* Perform first-fit algorhtym on reservations into buckets.
*
* Return array indexed by item delta of array of filled buckets.
*/
public function bestFit($dates) {
$entity = $this->entity;
$context = $this->context;
$best_fit = array();
$parent_conflicts = parent::conflicts($dates);
$date_value = $dates['value'];
foreach ($this->items as $delta => $item) {
// No need to sort into buckets if there is nothing to sort into buckets.
if (!array_key_exists($delta, $parent_conflicts) or !array_key_exists($date_value, $parent_conflicts[$delta])) {
continue;
}
// Determine if the quantity field exists. If so use it.
try {
$quantity = $item->{$context['quantity_field']}
->value();
} catch (EntityMetadataWrapperException $e) {
$quantity = 1;
}
// Split reservations based on quantity.
$reservations = array();
foreach ($parent_conflicts[$delta][$date_value] as $reservation) {
for ($i = 0; $i < $reservation->quantity; $i++) {
$reservations[] = $reservation;
}
}
// Determine how many bucket items are needed for this time period.
// Need to sort like this:
// .... time ....
// item1 x x a a a x x x x x f x e e e x x x x x
// item2 x x x d d d d d d x x x x c c c x x x x
// item3 x x b b b b b b b b b b b b b x x x x x
// etc ......
//
// // Order by lenght of reservation descending.
// // Do first-fit algorythm.
// Sort by length of reservation.
uasort($reservations, array(
$this,
"merci_bucket_cmp_length",
));
$buckets = array();
// First-fit algorythm.
foreach ($reservations as $test_reservation) {
// Go through each bucket item to look for a available slot for this reservation.
//
// Find a bucket to use for this reservation.
for ($i = 0; $i < $quantity; $i++) {
$fits = TRUE;
// Bucket already has other reservations we need to check against for a fit.
if (array_key_exists($i, $buckets)) {
foreach ($buckets[$i] as $reservation) {
if ($this
->merci_bucket_intersects($reservation, $test_reservation)) {
//Conflict so skip saving the reservation to this slot and try to use the next bucket item.
$fits = FALSE;
break;
}
}
}
// We've found a slot so test the next reservation.
if ($fits) {
if (array_key_exists($i, $buckets)) {
$buckets[$i] = array();
}
$buckets[$i][] = $test_reservation;
break;
}
}
}
if (count($buckets)) {
$best_fit[$delta] = $buckets;
}
}
return $best_fit;
}
/*
* |----------------------| range 1
* |---> range 2 overlap
* |---> range 2 overlap
* |---> range 2 overlap
* |---> range 2 no overlap
*/
private function merci_bucket_intersects($r1, $r2) {
$value = $this->date_column;
$value2 = $this->date_column2;
/*
* Make sure r1 start date is before r2 start date.
*/
if (date_create($r1->{$value}) > date_create($r2->{$value})) {
$temp = $r1;
$r1 = $r2;
$r2 = $temp;
}
if (date_create($r2->{$value}) <= date_create($r1->{$value2})) {
return true;
}
return false;
}
private function merci_bucket_cmp_length($a, $b) {
$value = $this->date_column;
$value2 = $this->date_column2;
$len_a = date_format(date_create($a->{$value2}), 'U') - date_format(date_create($a->{$value}), 'U');
$len_b = date_format(date_create($b->{$value2}), 'U') - date_format(date_create($b->{$value}), 'U');
if ($len_a == $len_b) {
return 0;
}
return $len_a < $len_b ? 1 : -1;
}
}