Skip to content

Commit

Permalink
Schedule Criteria: Merge criteria of the same type (#2876)
Browse files Browse the repository at this point in the history
  • Loading branch information
nadzpogi authored Jan 27, 2025
1 parent c7a3eaf commit e97953e
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 59 deletions.
31 changes: 31 additions & 0 deletions lib/Connector/NationalWeatherServiceConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Xibo\Event\ScheduleCriteriaRequestEvent;
use Xibo\Event\ScheduleCriteriaRequestInterface;
use Xibo\Event\WidgetDataRequestEvent;
use Xibo\Factory\DisplayFactory;
use Xibo\Support\Exception\ConfigurationException;
use Xibo\Support\Sanitizer\SanitizerInterface;
use Xibo\Widget\Provider\DataProviderInterface;
use Xibo\XMR\ScheduleCriteriaUpdateAction;
Expand Down Expand Up @@ -72,6 +75,7 @@ public function setFactories(ContainerInterface $container): ConnectorInterface
public function registerWithDispatcher(EventDispatcherInterface $dispatcher): ConnectorInterface
{
$dispatcher->addListener(WidgetDataRequestEvent::$NAME, [$this, 'onDataRequest']);
$dispatcher->addListener(ScheduleCriteriaRequestEvent::$NAME, [$this, 'onScheduleCriteriaRequest']);
return $this;
}

Expand Down Expand Up @@ -386,4 +390,31 @@ private function matchesFilter(string $actualValue, string $expectedValue): bool

return false;
}

/**
* @param ScheduleCriteriaRequestInterface $event
* @return void
* @throws ConfigurationException
*/
public function onScheduleCriteriaRequest(ScheduleCriteriaRequestInterface $event): void
{
// Initialize Emergency Alerts schedule criteria parameters but with limited category
$event->addType('emergency_alerts', __('Emergency Alerts'))
->addMetric('emergency_alert_status', __('Status'))
->addCondition([
'eq' => __('Equal to')
])
->addValues('dropdown', [
self::ACTUAL_ALERT => __('Actual Alerts'),
self::TEST_ALERT => __('Test Alerts'),
self::NO_ALERT => __('No Alerts')
])
->addMetric('emergency_alert_category', __('Category'))
->addCondition([
'eq' => __('Equal to')
])
->addValues('dropdown', [
'Met' => __('Met')
]);
}
}
142 changes: 109 additions & 33 deletions lib/Event/ScheduleCriteriaRequestEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
class ScheduleCriteriaRequestEvent extends Event implements ScheduleCriteriaRequestInterface
{
public static $NAME = 'schedule.criteria.request';
private $criteria = [];
private $currentTypeIndex = null;
private $currentMetric = null;
private array $criteria = [];
private ?int $currentTypeIndex = null;
private array $currentMetric = [];
private array $defaultConditions = [];

public function __construct()
Expand All @@ -58,7 +58,21 @@ public function __construct()
*/
public function addType(string $id, string $type): self
{
// Initialize the type in the criteria array
// Ensure that 'types' key exists
if (!isset($this->criteria['types'])) {
$this->criteria['types'] = [];
}

// Check if the type already exists
foreach ($this->criteria['types'] as $index => $existingType) {
if ($existingType['id'] === $id) {
// If the type exists, update currentTypeIndex and return
$this->currentTypeIndex = $index;
return $this;
}
}

// If the type doesn't exist, add it in the criteria array
$this->criteria['types'][] = [
'id' => $id,
'name' => $type,
Expand All @@ -75,21 +89,38 @@ public function addType(string $id, string $type): self
*/
public function addMetric(string $id, string $name): self
{
// Ensure the current type is set
if (!isset($this->criteria['types'][$this->currentTypeIndex])) {
throw new ConfigurationException(__('Current type is not set.'));
}

// initialize the metric to add
$metric = [
'id' => $id,
'name' => $name,
'conditions' => $this->formatConditions($this->defaultConditions),
'isUsingDefaultConditions' => true,
'values' => null
];

// Add the metric to the current type
if (isset($this->criteria['types'][$this->currentTypeIndex])) {
$this->criteria['types'][$this->currentTypeIndex]['metrics'][] = $metric;
$this->currentMetric = $metric;
} else {
throw new ConfigurationException(__('Current type is not set.'));
// Reference the current type's metrics
$metrics = &$this->criteria['types'][$this->currentTypeIndex]['metrics'];

// Check if the metric already exists
foreach ($metrics as &$existingMetric) {
if ($existingMetric['id'] === $id) {
// If the metric exists, set currentMetric and return
$this->currentMetric = $existingMetric;
return $this;
}
}

// If the metric doesn't exist, add it to the metrics array
$metrics[] = $metric;

// Set the current metric for chaining
$this->currentMetric = $metric;

return $this;
}

Expand All @@ -99,6 +130,11 @@ public function addMetric(string $id, string $name): self
*/
public function addCondition(array $conditions): self
{
// Retain default conditions if provided condition array is empty
if (empty($conditions)) {
return $this;
}

// Ensure current type is set
if (!isset($this->criteria['types'][$this->currentTypeIndex])) {
throw new ConfigurationException(__('Current type is not set.'));
Expand All @@ -111,10 +147,30 @@ public function addCondition(array $conditions): self
}
}

// Assign conditions to the current metric
foreach ($this->criteria['types'][$this->currentTypeIndex]['metrics'] as &$metric) {
if ($metric['name'] === $this->currentMetric['name']) {
$metric['conditions'] = $this->formatConditions($conditions);
// Reference the current type's metrics
$metrics = &$this->criteria['types'][$this->currentTypeIndex]['metrics'];

// Find the current metric and handle conditions
foreach ($metrics as &$metric) {
if ($metric['id'] === $this->currentMetric['id']) {
if ($metric['isUsingDefaultConditions']) {
// If metric is using default conditions, replace with new ones
$metric['conditions'] = $this->formatConditions($conditions);
$metric['isUsingDefaultConditions'] = false;
} else {
// Merge the new conditions with existing ones, avoiding duplicates
$existingConditions = $metric['conditions'];
$newConditions = $this->formatConditions($conditions);

// Combine the two condition arrays
$mergedConditions = array_merge($existingConditions, $newConditions);

// Remove duplicates
$finalConditions = array_unique($mergedConditions, SORT_REGULAR);

$metric['conditions'] = array_values($finalConditions);
}

break;
}
}
Expand Down Expand Up @@ -146,34 +202,54 @@ private function formatConditions(array $conditions): array
*/
public function addValues(string $inputType, array $values): self
{
// Ensure current type is set
if (!isset($this->criteria['types'][$this->currentTypeIndex])) {
throw new ConfigurationException(__('Current type is not set.'));
}

// Restrict input types to 'dropdown', 'number', 'text' and 'date'
$allowedInputTypes = ['dropdown', 'number', 'text', 'date'];
if (!in_array($inputType, $allowedInputTypes)) {
throw new ConfigurationException(__('Invalid input type.'));
}

// Add values to the current metric
if (isset($this->criteria['types'][$this->currentTypeIndex])) {
foreach ($this->criteria['types'][$this->currentTypeIndex]['metrics'] as &$metric) {
// check if the current metric matches the metric from the current iteration
if ($metric['name'] === $this->currentMetric['name']) {
// format the values to separate id and title
$formattedValues = [];
foreach ($values as $id => $title) {
$formattedValues[] = [
'id' => $id,
'title' => $title
];
}

$metric['values'] = [
'inputType' => $inputType,
'values' => $formattedValues
// Reference the metrics of the current type
$metrics = &$this->criteria['types'][$this->currentTypeIndex]['metrics'];

// Find the current metric and add or update values
foreach ($metrics as &$metric) {
if ($metric['id'] === $this->currentMetric['id']) {
// Check if the input type matches the existing one (if any)
if (isset($metric['values']['inputType']) && $metric['values']['inputType'] !== $inputType) {
throw new ConfigurationException(__('Input type does not match.'));
}

// Format the new values
$formattedValues = [];
foreach ($values as $id => $title) {
$formattedValues[] = [
'id' => $id,
'title' => $title
];
}

// Merge new values with existing ones, avoiding duplicates
$existingValues = $metric['values']['values'] ?? [];

// Combine the two value arrays
$mergedValues = array_merge($existingValues, $formattedValues);

// Remove duplicates
$uniqueFormattedValues = array_unique($mergedValues, SORT_REGULAR);

// Update the metric's values
$metric['values'] = [
'inputType' => $inputType,
'values' => array_values($uniqueFormattedValues)
];

break;
}
} else {
throw new ConfigurationException(__('Current type is not set.'));
}

return $this;
Expand Down
Loading

0 comments on commit e97953e

Please sign in to comment.