1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace Atk4\Ui\Table\Column\FilterModel;
6:
7: use Atk4\Data\Model;
8: use Atk4\Ui\Form;
9: use Atk4\Ui\Table\Column;
10:
11: class TypeDate extends Column\FilterModel
12: {
13: #[\Override]
14: protected function init(): void
15: {
16: parent::init();
17:
18: $this->op->values = [
19: '=' => 'Is',
20: 'within' => 'Is within',
21: '<' => 'Is before',
22: '>' => 'Is after',
23: '<=' => 'Is on or before',
24: '>=' => 'Is on or after',
25: '!=' => 'Is not',
26: 'empty' => 'Is empty',
27: 'not empty' => 'Is not empty',
28: ];
29: $this->op->default = '=';
30:
31: // the date value to operate on
32: $this->value->values = [
33: 'today' => 'Today',
34: 'tomorrow' => 'Tomorrow',
35: 'yesterday' => 'Yesterday',
36: '-1 week' => 'One week ago',
37: '+1 week' => 'One week from now',
38: '-1 month' => 'One month ago',
39: '+1 month' => 'One month from now',
40: 'x_day_ago' => 'Numbers of days ago',
41: 'x_day_now' => 'Number of days from now',
42: 'exact' => 'Exact date',
43: ];
44:
45: // the range value field use when within is select
46: $this->addField('range', [
47: 'ui' => ['caption' => ''],
48: 'values' => [
49: '-1 week' => 'The past week',
50: '-1 month' => 'The past month',
51: '-1 year' => 'The past year',
52: '+1 week' => 'The next week',
53: '+1 month' => 'The next month',
54: '+1 year' => 'The next year',
55: 'x_day_before' => 'The next numbers of days before',
56: 'x_day_after' => 'The next number of days after',
57: ],
58: ]);
59:
60: // the exact date field input when exact is select as input value
61: $this->addField('exact_date', ['type' => 'date', 'ui' => ['caption' => '']]);
62:
63: // the integer field to generate a date when x day selector is used
64: $this->addField('number_days', ['ui' => ['caption' => '', 'form' => [Form\Control\Line::class, 'inputType' => 'number']]]);
65: }
66:
67: #[\Override]
68: public function setConditionForModel(Model $model)
69: {
70: $filter = $this->recallData();
71: if ($filter !== null) {
72: switch ($filter['op']) {
73: case 'empty':
74: $model->addCondition($filter['name'], '=', null);
75:
76: break;
77: case 'not empty':
78: $model->addCondition($filter['name'], '!=', null);
79:
80: break;
81: case 'within':
82: $d1 = $this->getDate($filter['value']);
83: $d2 = $this->getDate($filter['range']);
84: if ($d2 >= $d1) {
85: $value = $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d1);
86: $value2 = $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d2);
87: } else {
88: $value = $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d2);
89: $value2 = $model->getPersistence()->typecastSaveField($model->getField($filter['name']), $d1);
90: }
91: $model->addCondition($model->expr('[field] between [value] and [value2]', [
92: 'field' => $model->getField($filter['name']),
93: 'value' => $value,
94: 'value2' => $value2,
95: ]));
96:
97: break;
98: default:
99: $model->addCondition($filter['name'], $filter['op'], $this->getDate($filter['value']));
100: }
101: }
102:
103: return $model;
104: }
105:
106: /**
107: * Get date object according to it's modifier string.
108: * Will construct and return a date object base on constructor string.
109: *
110: * @param string $dateModifier the string to pass to generated a date from
111: *
112: * @return \DateTime
113: */
114: public function getDate($dateModifier)
115: {
116: switch ($dateModifier) {
117: case 'exact':
118: $date = $this->get('exact_date');
119:
120: break;
121: case 'x_day_ago':
122: case 'x_day_before':
123: $date = new \DateTime('-' . $this->get('number_days') . ' days');
124:
125: break;
126: case 'x_day_now':
127: case 'x_day_after':
128: $date = new \DateTime('+' . $this->get('number_days') . ' days');
129:
130: break;
131: default:
132: $date = $dateModifier ? new \DateTime($dateModifier) : null;
133: }
134:
135: return $date;
136: }
137:
138: #[\Override]
139: public function getFormDisplayRules(): array
140: {
141: return [
142: 'range' => ['op' => 'isExactly[within]'],
143: 'exact_date' => ['value' => 'isExactly[exact]'],
144: 'number_days' => [['value' => 'isExactly[x_day_ago]'], ['value' => 'isExactly[x_day_now]']],
145: ];
146: }
147: }
148: