diff -u b/modules/recurring_events_registration/recurring_events_registration.views.inc b/modules/recurring_events_registration/recurring_events_registration.views.inc --- b/modules/recurring_events_registration/recurring_events_registration.views.inc +++ b/modules/recurring_events_registration/recurring_events_registration.views.inc @@ -37,6 +37,13 @@ 'field' => 'event_registration__capacity', 'id' => 'eventinstance_registration_availability_count', ], + 'argument' => [ + 'title' => t('Registration Availability Count'), + 'help' => t('The number of registration spaces available for an event instance.'), + 'field' => 'event_registration__capacity', + 'id' => 'eventinstance_registration_availability_count', + 'filter' => 'intval', + ], ]; $data['eventinstance_field_data']['capacity'] = [ diff -u b/modules/recurring_events_registration/src/Plugin/views/filter/EventInstanceRegistrationAvailabilityCount.php b/modules/recurring_events_registration/src/Plugin/views/filter/EventInstanceRegistrationAvailabilityCount.php --- b/modules/recurring_events_registration/src/Plugin/views/filter/EventInstanceRegistrationAvailabilityCount.php +++ b/modules/recurring_events_registration/src/Plugin/views/filter/EventInstanceRegistrationAvailabilityCount.php @@ -2,8 +2,6 @@ namespace Drupal\recurring_events_registration\Plugin\views\filter; -use Drupal\Component\Utility\Xss; -use Drupal\Core\Form\FormStateInterface; use Drupal\views\Plugin\views\filter\NumericFilter; use Symfony\Component\DependencyInjection\ContainerInterface; use Drupal\recurring_events_registration\RegistrationCreationService; @@ -58,31 +56,6 @@ /** * {@inheritdoc} */ - public function operators() { - $operators = parent::operators(); - // Offer limited operators. - return array_intersect_key($operators, array_flip([ - '>', - '<', - '=', - '!=', - '<=', - '>=', - ])); - } - - /** - * {@inheritdoc} - */ - protected function valueForm(&$form, FormStateInterface $form_state) { - parent::valueForm($form, $form_state); - unset ($form['value']['min']); - unset ($form['value']['max']); - } - - /** - * {@inheritdoc} - */ public function query() { // Set -1 as the default value so that if no events match the checks, then // we should get no results, rather than all results. @@ -95,7 +68,7 @@ // Remove any instances of this filter from the filters. if (!empty($filters)) { foreach ($filters as $key => $filter) { - if ($filter instanceof EventInstanceRegistrationAvailability) { + if ($filter instanceof EventInstanceRegistrationAvailabilityCount) { unset($view->filter[$key]); } } @@ -107,20 +80,55 @@ $view->preExecute(); $view->execute(); - $value = $this->value; - error_log(print_r($value, TRUE)); - return; - $value = Xss::filter($value); - - $operator = $this->operator; + $value = $this->value['value'] ?? NULL; + $min = $this->value['min'] ?? NULL; + $max = $this->value['max'] ?? NULL; if (!empty($view->result)) { + // Loop through results, evaluate result's availability re: filter settings. foreach ($view->result as $key => $result) { $this->registrationCreationService->setEventInstance($result->_entity); $availability = $this->registrationCreationService->retrieveAvailability(); - error_log("$availability $operator $value"); - if (eval("return $availability $operator $value")) { + $filter_result = FALSE; + + switch ($this->operator) { + case '<': + $filter_result = $availability < $value; + break; + case '<=': + $filter_result = $availability <= $value; + break; + case '=': + $filter_result = $availability == $value; + break; + case '!=': + $filter_result = $availability != $value; + break; + case '>=': + $filter_result = $availability >= $value; + break; + case '>': + $filter_result = $availability > $value; + break; + case 'between': + $filter_result = $min <= $availability && $availability <= $max; + break; + case 'not between': + $filter_result = !($min <= $availability && $availability <= $max); + break; + case 'regular_expression': + $filter_result = preg_match($value, $availability); + break; + case 'empty': + $filter_result = !$availability; + break; + case 'not empty': + $filter_result = !!$availability; + break; + } + + if ($filter_result) { $items[] = $result->_entity->id(); } } only in patch2: unchanged: --- /dev/null +++ b/modules/recurring_events_registration/config/schema/recurring_events_registration.views.schema.yml @@ -0,0 +1,8 @@ +views.filter.eventinstance_registration_availability_count: + type: views.filter.numeric + +views.filter_value.eventinstance_registration_availability_count: + type: views.filter_value.numeric + +views.argument.eventinstance_registration_availability_count: + type: views.argument.numeric only in patch2: unchanged: --- /dev/null +++ b/modules/recurring_events_registration/src/Plugin/views/argument/EventInstanceRegistrationAvailabilityCount.php @@ -0,0 +1,119 @@ +registrationCreationService = $registration_creation_service; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('recurring_events_registration.creation_service') + ); + } + + /** + * {@inheritdoc} + */ + public function query($group_by = FALSE) { + // Set -1 as the default value so that if no events match the checks, then + // we should get no results, rather than all results. + $items = ['-1']; + $table = $this->ensureMyTable(); + + // Grab the current view being executed. + $view = clone $this->query->view; + $filters = $view->argument; + // Remove any instances of this filter from the filters. + if (!empty($filters)) { + foreach ($filters as $key => $filter) { + if ($filter instanceof \Drupal\recurring_events_registration\Plugin\views\argument\EventInstanceRegistrationAvailabilityCount) { + unset($view->argument[$key]); + } + } + } + // Execute the current view with the filters removed, so we can reduce the + // number of event instances we need to examine to find their availability. + // This makes the query more efficient and avoids having to do messy union + // selects across multiple tables to determine the availability of an event. + $view->preExecute(); + $view->execute(); + + if (!empty($this->options['break_phrase'])) { + $break = static::breakString($this->argument, FALSE); + $this->value = $break->value; + $this->operator = $break->operator; + } else { + $this->value = [$this->argument]; + } + + if (!empty($view->result)) { + // Loop through results, evaluate result's availability re: filter settings. + foreach ($view->result as $key => $result) { + $this->registrationCreationService->setEventInstance($result->_entity); + $availability = $this->registrationCreationService->retrieveAvailability(); + + $filter_result = FALSE; + + if (count($this->value) > 1) { + $filter_result = array_search($availability, $this->value) !== FALSE; + } + else { + $filter_result = $availability == $this->argument; + } + + if (!empty($this->options['not'])) { + $filter_result = !$filter_result; + } + + if ($filter_result) { + $items[] = $result->_entity->id(); + } + } + } + + // Filter this view by the events which match the availability above. + $items = implode(',', $items); + $this->query->addWhereExpression(0, "$table.id IN (" . $items . ")"); + } + +}