Skip to content

Commit e97953e

Browse files
authored
Schedule Criteria: Merge criteria of the same type (#2876)
relates to xibosignageltd/xibo-private#908
1 parent c7a3eaf commit e97953e

File tree

3 files changed

+219
-59
lines changed

3 files changed

+219
-59
lines changed

lib/Connector/NationalWeatherServiceConnector.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@
3232
use Psr\Container\ContainerInterface;
3333
use Psr\Container\NotFoundExceptionInterface;
3434
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
35+
use Xibo\Event\ScheduleCriteriaRequestEvent;
36+
use Xibo\Event\ScheduleCriteriaRequestInterface;
3537
use Xibo\Event\WidgetDataRequestEvent;
3638
use Xibo\Factory\DisplayFactory;
39+
use Xibo\Support\Exception\ConfigurationException;
3740
use Xibo\Support\Sanitizer\SanitizerInterface;
3841
use Xibo\Widget\Provider\DataProviderInterface;
3942
use Xibo\XMR\ScheduleCriteriaUpdateAction;
@@ -72,6 +75,7 @@ public function setFactories(ContainerInterface $container): ConnectorInterface
7275
public function registerWithDispatcher(EventDispatcherInterface $dispatcher): ConnectorInterface
7376
{
7477
$dispatcher->addListener(WidgetDataRequestEvent::$NAME, [$this, 'onDataRequest']);
78+
$dispatcher->addListener(ScheduleCriteriaRequestEvent::$NAME, [$this, 'onScheduleCriteriaRequest']);
7579
return $this;
7680
}
7781

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

387391
return false;
388392
}
393+
394+
/**
395+
* @param ScheduleCriteriaRequestInterface $event
396+
* @return void
397+
* @throws ConfigurationException
398+
*/
399+
public function onScheduleCriteriaRequest(ScheduleCriteriaRequestInterface $event): void
400+
{
401+
// Initialize Emergency Alerts schedule criteria parameters but with limited category
402+
$event->addType('emergency_alerts', __('Emergency Alerts'))
403+
->addMetric('emergency_alert_status', __('Status'))
404+
->addCondition([
405+
'eq' => __('Equal to')
406+
])
407+
->addValues('dropdown', [
408+
self::ACTUAL_ALERT => __('Actual Alerts'),
409+
self::TEST_ALERT => __('Test Alerts'),
410+
self::NO_ALERT => __('No Alerts')
411+
])
412+
->addMetric('emergency_alert_category', __('Category'))
413+
->addCondition([
414+
'eq' => __('Equal to')
415+
])
416+
->addValues('dropdown', [
417+
'Met' => __('Met')
418+
]);
419+
}
389420
}

lib/Event/ScheduleCriteriaRequestEvent.php

Lines changed: 109 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232
class ScheduleCriteriaRequestEvent extends Event implements ScheduleCriteriaRequestInterface
3333
{
3434
public static $NAME = 'schedule.criteria.request';
35-
private $criteria = [];
36-
private $currentTypeIndex = null;
37-
private $currentMetric = null;
35+
private array $criteria = [];
36+
private ?int $currentTypeIndex = null;
37+
private array $currentMetric = [];
3838
private array $defaultConditions = [];
3939

4040
public function __construct()
@@ -58,7 +58,21 @@ public function __construct()
5858
*/
5959
public function addType(string $id, string $type): self
6060
{
61-
// Initialize the type in the criteria array
61+
// Ensure that 'types' key exists
62+
if (!isset($this->criteria['types'])) {
63+
$this->criteria['types'] = [];
64+
}
65+
66+
// Check if the type already exists
67+
foreach ($this->criteria['types'] as $index => $existingType) {
68+
if ($existingType['id'] === $id) {
69+
// If the type exists, update currentTypeIndex and return
70+
$this->currentTypeIndex = $index;
71+
return $this;
72+
}
73+
}
74+
75+
// If the type doesn't exist, add it in the criteria array
6276
$this->criteria['types'][] = [
6377
'id' => $id,
6478
'name' => $type,
@@ -75,21 +89,38 @@ public function addType(string $id, string $type): self
7589
*/
7690
public function addMetric(string $id, string $name): self
7791
{
92+
// Ensure the current type is set
93+
if (!isset($this->criteria['types'][$this->currentTypeIndex])) {
94+
throw new ConfigurationException(__('Current type is not set.'));
95+
}
96+
97+
// initialize the metric to add
7898
$metric = [
7999
'id' => $id,
80100
'name' => $name,
81101
'conditions' => $this->formatConditions($this->defaultConditions),
102+
'isUsingDefaultConditions' => true,
82103
'values' => null
83104
];
84105

85-
// Add the metric to the current type
86-
if (isset($this->criteria['types'][$this->currentTypeIndex])) {
87-
$this->criteria['types'][$this->currentTypeIndex]['metrics'][] = $metric;
88-
$this->currentMetric = $metric;
89-
} else {
90-
throw new ConfigurationException(__('Current type is not set.'));
106+
// Reference the current type's metrics
107+
$metrics = &$this->criteria['types'][$this->currentTypeIndex]['metrics'];
108+
109+
// Check if the metric already exists
110+
foreach ($metrics as &$existingMetric) {
111+
if ($existingMetric['id'] === $id) {
112+
// If the metric exists, set currentMetric and return
113+
$this->currentMetric = $existingMetric;
114+
return $this;
115+
}
91116
}
92117

118+
// If the metric doesn't exist, add it to the metrics array
119+
$metrics[] = $metric;
120+
121+
// Set the current metric for chaining
122+
$this->currentMetric = $metric;
123+
93124
return $this;
94125
}
95126

@@ -99,6 +130,11 @@ public function addMetric(string $id, string $name): self
99130
*/
100131
public function addCondition(array $conditions): self
101132
{
133+
// Retain default conditions if provided condition array is empty
134+
if (empty($conditions)) {
135+
return $this;
136+
}
137+
102138
// Ensure current type is set
103139
if (!isset($this->criteria['types'][$this->currentTypeIndex])) {
104140
throw new ConfigurationException(__('Current type is not set.'));
@@ -111,10 +147,30 @@ public function addCondition(array $conditions): self
111147
}
112148
}
113149

114-
// Assign conditions to the current metric
115-
foreach ($this->criteria['types'][$this->currentTypeIndex]['metrics'] as &$metric) {
116-
if ($metric['name'] === $this->currentMetric['name']) {
117-
$metric['conditions'] = $this->formatConditions($conditions);
150+
// Reference the current type's metrics
151+
$metrics = &$this->criteria['types'][$this->currentTypeIndex]['metrics'];
152+
153+
// Find the current metric and handle conditions
154+
foreach ($metrics as &$metric) {
155+
if ($metric['id'] === $this->currentMetric['id']) {
156+
if ($metric['isUsingDefaultConditions']) {
157+
// If metric is using default conditions, replace with new ones
158+
$metric['conditions'] = $this->formatConditions($conditions);
159+
$metric['isUsingDefaultConditions'] = false;
160+
} else {
161+
// Merge the new conditions with existing ones, avoiding duplicates
162+
$existingConditions = $metric['conditions'];
163+
$newConditions = $this->formatConditions($conditions);
164+
165+
// Combine the two condition arrays
166+
$mergedConditions = array_merge($existingConditions, $newConditions);
167+
168+
// Remove duplicates
169+
$finalConditions = array_unique($mergedConditions, SORT_REGULAR);
170+
171+
$metric['conditions'] = array_values($finalConditions);
172+
}
173+
118174
break;
119175
}
120176
}
@@ -146,34 +202,54 @@ private function formatConditions(array $conditions): array
146202
*/
147203
public function addValues(string $inputType, array $values): self
148204
{
205+
// Ensure current type is set
206+
if (!isset($this->criteria['types'][$this->currentTypeIndex])) {
207+
throw new ConfigurationException(__('Current type is not set.'));
208+
}
209+
149210
// Restrict input types to 'dropdown', 'number', 'text' and 'date'
150211
$allowedInputTypes = ['dropdown', 'number', 'text', 'date'];
151212
if (!in_array($inputType, $allowedInputTypes)) {
152213
throw new ConfigurationException(__('Invalid input type.'));
153214
}
154215

155-
// Add values to the current metric
156-
if (isset($this->criteria['types'][$this->currentTypeIndex])) {
157-
foreach ($this->criteria['types'][$this->currentTypeIndex]['metrics'] as &$metric) {
158-
// check if the current metric matches the metric from the current iteration
159-
if ($metric['name'] === $this->currentMetric['name']) {
160-
// format the values to separate id and title
161-
$formattedValues = [];
162-
foreach ($values as $id => $title) {
163-
$formattedValues[] = [
164-
'id' => $id,
165-
'title' => $title
166-
];
167-
}
168-
169-
$metric['values'] = [
170-
'inputType' => $inputType,
171-
'values' => $formattedValues
216+
// Reference the metrics of the current type
217+
$metrics = &$this->criteria['types'][$this->currentTypeIndex]['metrics'];
218+
219+
// Find the current metric and add or update values
220+
foreach ($metrics as &$metric) {
221+
if ($metric['id'] === $this->currentMetric['id']) {
222+
// Check if the input type matches the existing one (if any)
223+
if (isset($metric['values']['inputType']) && $metric['values']['inputType'] !== $inputType) {
224+
throw new ConfigurationException(__('Input type does not match.'));
225+
}
226+
227+
// Format the new values
228+
$formattedValues = [];
229+
foreach ($values as $id => $title) {
230+
$formattedValues[] = [
231+
'id' => $id,
232+
'title' => $title
172233
];
173234
}
235+
236+
// Merge new values with existing ones, avoiding duplicates
237+
$existingValues = $metric['values']['values'] ?? [];
238+
239+
// Combine the two value arrays
240+
$mergedValues = array_merge($existingValues, $formattedValues);
241+
242+
// Remove duplicates
243+
$uniqueFormattedValues = array_unique($mergedValues, SORT_REGULAR);
244+
245+
// Update the metric's values
246+
$metric['values'] = [
247+
'inputType' => $inputType,
248+
'values' => array_values($uniqueFormattedValues)
249+
];
250+
251+
break;
174252
}
175-
} else {
176-
throw new ConfigurationException(__('Current type is not set.'));
177253
}
178254

179255
return $this;

0 commit comments

Comments
 (0)