From fcbf4084468b6387938e6c30ded4fa8bdfb98dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20San=20Miguel=20Garc=C3=ADa?= Date: Sun, 5 Mar 2023 19:30:23 -0600 Subject: [PATCH] wip for prerelease --- FieldtypeRecurringDates.module | 88 ++++-- InputfieldRecurringDates.js | 8 +- InputfieldRecurringDates.module | 282 ++++++++++-------- OccurrenceArray.php | 9 +- .../RecurringDatesFinder.module | 36 ++- composer.json | 2 +- partials/AlpineComponent.php | 3 +- 7 files changed, 250 insertions(+), 178 deletions(-) diff --git a/FieldtypeRecurringDates.module b/FieldtypeRecurringDates.module index 971e5e1..7546d13 100644 --- a/FieldtypeRecurringDates.module +++ b/FieldtypeRecurringDates.module @@ -49,19 +49,23 @@ class FieldtypeRecurringDates extends FieldtypeMulti parent::__construct(); } - public function init() + public function init(){ + $this->addHook('/fieldtype-recurring-dates/get-dates/', $this, 'hookGetDates'); + } + + public function ready() { - $this->addHook('/fieldtype-recurring-dates/get-dates/', $this, 'hookGetDates'); $this->addHookAfter('Fields::added', $this, 'hookAfterFieldAdded'); $this->addHookAfter('Fields::deleted', $this, 'hookAfterFieldDeleted'); $this->addHookAfter('Fields::deleted', $this, 'hookAfterFieldDeleted'); $this->addHookBefore('Pages::deleted', $this, 'hookAfterPageDelete'); } - public function hookGetDates($event){ + public function hookGetDates($event) + { - if(!$event->user->isLoggedin()) return false; + if (!$event->user->isLoggedin()) return false; $input = $event->input; $page = $input->get->int('id'); @@ -69,7 +73,7 @@ class FieldtypeRecurringDates extends FieldtypeMulti $start = $input->get->int('start'); $limit = $input->get->int('limit'); - if(!$page || !$field) return "{}"; + if (!$page || !$field) return "{}"; $field_name = $event->fields->get($field)->name; $page = $event->pages->get($page); @@ -86,6 +90,7 @@ class FieldtypeRecurringDates extends FieldtypeMulti */ public function hookAfterFieldAdded($event) { + bd('extra table added'); $item = $event->arguments(0); if ($item->type->name == $this->name) { $table_name = $this->getExtrasTableName($item); @@ -108,26 +113,38 @@ class FieldtypeRecurringDates extends FieldtypeMulti } } + + /** + * Deletes the settings row for the database + * + * @param HookEvent $event + * @return void + * + */ public function hookAfterPageDelete($event) { - $pages = $event->object; $page = $event->arguments(0); - $options = $event->arguments(1); $recurring_fields = $page->getFields()->find("type={$this->name}"); foreach ($recurring_fields as $f) { $this->deleteSettings($page, $f); } } + /** + * Deletes the table where settings for the inputfield are saved + * + * @return void + * + */ public function hookAfterFieldDeleted($event) { $item = $event->arguments(0); if ($item->type->name == $this->name) { $table_name = $this->getExtrasTableName($item); - $create_rrules_table = ""; - $create_rrules_table .= "DROP TABLE IF EXISTS $table_name;"; + $delete_rrules_table = ""; + $delete_rrules_table .= "DROP TABLE IF EXISTS $table_name"; try { - $query = $this->database->prepare($create_rrules_table); + $query = $this->database->prepare($delete_rrules_table); $query->execute(); } catch (\Exception $e) { $this->database->error($e->getMessage()); @@ -136,14 +153,14 @@ class FieldtypeRecurringDates extends FieldtypeMulti } - public function getRruleOCurrences($value) + public function getRruleOcurrences($value) { $rrule = new RRule($value); return $rrule; } /** - * Return the database schema that defines an Ocurrence + * Return the database schema that defines an Occurrence * * @param Field $field * @return array @@ -186,7 +203,6 @@ class FieldtypeRecurringDates extends FieldtypeMulti public function getBlankValue(Page $page, Field $field) { return new RecurringDate(); - //return new OccurrenceArray(); } /** @@ -227,17 +243,28 @@ class FieldtypeRecurringDates extends FieldtypeMulti $recurring_date = $this->getBlankValue($page, $field); $recurring_date->settings = json_encode($recurring_date->settings, true); if (empty($value) || !is_array($value)) return $recurring_date; - bd($value); if ($this->isSettingsValue($value)) { $recurring_date->settings = $value['settings']; $rrule_value = json_decode($value['rrule'], true); + /*if (is_array($rrule_value['DTSTART'])) { + $d = new \DateTime($rrule_value['DTSTART']['date'], + new \DateTimeZone($rrule_value['DTSTART']['timezone'])); + $rrule_value['DTSTART'] = $d; + } + bd($rrule_value);*/ $rrule = new RRule($rrule_value); + //bd($rrule); $recurring_date->rrule = $rrule; } else { $settings = $this->getSettings($page, $field); - if($settings) { + if ($settings) { $recurring_date->settings = $settings->settings; $rrule_value = json_decode($settings->rrule, true); + /*if (is_array($rrule_value['DTSTART'])) { + $d = new \DateTime($rrule_value['DTSTART']['date'], + new \DateTimeZone($rrule_value['DTSTART']['timezone'])); + $rrule_value['DTSTART'] = $d; + }*/ $rrule = new RRule($rrule_value); $recurring_date->rrule = $rrule; } @@ -277,27 +304,31 @@ class FieldtypeRecurringDates extends FieldtypeMulti public function ___sleepValue(Page $page, Field $field, $value) { - + bd($value->rrule); + bd($value->settings); $sleepValue = array(); if ($value->rrule) { $this->saveSettings($page, $field, $value); + foreach ($value->rrule as $date) { + bd($date); + $occurrence_date = new Occurrence(); + $occurrence_date->excluded = false; + $occurrence_date->date = $date; + $value->occurrences->add($occurrence_date); + } } - //bd($page); if (!$value instanceof RecurringDate) return $sleepValue; + // make the events sort by date ascending // $value->occurrences->sort('date'); - // convert each Event to an array within sleepValue foreach ($value->occurrences as $occurrence) { - // if no date specified then skip it - if (!$occurrence->date) continue; - // if($occurrence->formatted) throw new WireException('Formatted events cannot be saved'); + $sleepValue[] = array( 'data' => $occurrence, // note: 'date' is becoming 'data' (with an 'a') 'excluded' => $occurrence->excluded ); } - return $sleepValue; } @@ -364,7 +395,6 @@ class FieldtypeRecurringDates extends FieldtypeMulti $database = $this->wire()->database; $schema = $this->getDatabaseSchema($field); - //$table = $database->escapeTable($field->table); $table = $this->getExtrasTableName($field); $stmt = null; @@ -407,7 +437,6 @@ class FieldtypeRecurringDates extends FieldtypeMulti return parent::___loadPageField($page, $field); } - } @@ -426,13 +455,15 @@ class FieldtypeRecurringDates extends FieldtypeMulti /** @var \PDOStatement $pdo */ $pdo = $this->database->prepare($sql); $pdo->bindValue(':pages_id', $page->id); - $pdo->bindValue(':rrule', json_encode($rdate->rrule->getRule())); + $rrule_array = $rdate->rrule->getRule(); + $rrule_array['DTSTART'] = (new \DateTime($rrule_array['DTSTART']))->format('Y-m-d H:i:s'); + $pdo->bindValue(':rrule', json_encode($rrule_array)); $pdo->bindValue(':settings', (string)$rdate->settings); $pdo->execute(); } /** - * Saves rrule string when field is saved. + * Deletes rrule JSON string when the page containing the field is deleted. * * @param Page $page * @param Field $field @@ -447,6 +478,11 @@ class FieldtypeRecurringDates extends FieldtypeMulti $pdo->execute(); } + /** + * @param Page $page + * @param Field $field + * @return string + */ protected function getSettings(Page $page, Field $field) { $sql = "SELECT rrule, settings FROM {$this->getExtrasTableName($field)} WHERE pages_id=:pages_id"; diff --git a/InputfieldRecurringDates.js b/InputfieldRecurringDates.js index 3dfcd82..408bd60 100644 --- a/InputfieldRecurringDates.js +++ b/InputfieldRecurringDates.js @@ -77,9 +77,6 @@ document.addEventListener('alpine:init', (e) => { this.data.pagination.limit = this.$el.dataset.inputfieldLimit; this.updateEventList(); - /*this.$watch('data.pagination', (prop) => { - this.updateEventList(); - });*/ this.$watch('rrule', (prop) => { this.saveString(); @@ -111,10 +108,7 @@ document.addEventListener('alpine:init', (e) => { this.rrule = JSON.parse(json_rrule); this._rrule = JSON.stringify(this.rrule); } else { - //console.log(this.rrule); - /*var now = new Date(); - now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); - this.rrule.DTSTART = now.toISOString().slice(0, 16);*/ + this.settings.limit_mode = "count"; } }, diff --git a/InputfieldRecurringDates.module b/InputfieldRecurringDates.module index 3da6b99..ffbfb10 100644 --- a/InputfieldRecurringDates.module +++ b/InputfieldRecurringDates.module @@ -11,133 +11,177 @@ use RRule\RRule; */ class InputfieldRecurringDates extends Inputfield { - public static function getModuleInfo() - { - return array( - 'title' => 'Recurring Dates', - 'version' => 001, - 'summary' => 'Field that lets you define a recurring date rule.', - 'icon' => 'calendar-o', - 'requires' => 'AlpineJS' - ); - } - - public function __construct() - { - parent::__construct(); - } - - public function init() - { - // Load Alpine.js in
+ public static function getModuleInfo() + { + return array( + 'title' => 'Recurring Dates', + 'version' => 001, + 'summary' => 'Field that lets you define a recurring date rule.', + 'icon' => 'calendar-o', + 'requires' => 'AlpineJS' + ); + } + + public function __construct() + { + parent::__construct(); + } + + public function init() + { + // Load Alpine.js in
$this->setAttribute('pageSize', 10); - $this->modules->AlpineJS; - } - - public function ___render() - { - /** @var RecurringDate $recurring_dates */ - $recurring_dates = $this->value; - $this->setAttribute('class', $this->getAttribute('class') . ' main-input uk-width-1-1'); - - $occurrences = $recurring_dates->occurrences; - if ($recurring_dates->rrule) { - $rule_json = json_encode($recurring_dates->rrule->getRule()); - } - - $this->setAttribute('class', 'uk-input main-input'); - if ($rule_json) { - $this->setAttribute('value', [$rule_json]); - } - $this->setAttribute('x-ref', 'main-input'); - $this->setAttribute('x-model', '_rrule'); - $this->setAttribute('data-rrule', $rule_json); - $this->setAttribute('type', 'hidden'); - $this->setAttribute('data-settings', $recurring_dates->settings); - - $out = ""; - $filePath = "{$this->config->paths->siteModules}FieldtypeRecurringDates/partials/AlpineComponent.php"; - $alpineComponent = wireRenderFile($filePath, [ - 'fieldtype' => $this->hasFieldtype, - 'inputfield' => $this, - 'occurrences' => $occurrences, - 'inputfieldValue' => $recurring_dates - ]); - - $out .= $alpineComponent; - return $out; - } - - - public function ___renderValue() - { - $fieldtype = $this->hasFieldtype; - return $fieldtype->markupValue($this->hasPage, $this->hasField, $this->value); - } - - public function __getEventsUrl(){ + $this->set('startDateInput', 'date'); + $this->modules->AlpineJS; + } + + public function ___render() + { + /** @var RecurringDate $recurring_dates */ + $recurring_dates = $this->value; + $this->setAttribute('class', $this->getAttribute('class') . ' main-input uk-width-1-1'); + $occurrences = $recurring_dates->occurrences; + + if($recurring_dates->rrule){ + $rrule_array = $recurring_dates->rrule->getRule(); + + if ($this->startDateInput == "datetime") { + $rrule_array['DTSTART'] = (new \DateTime($rrule_array['DTSTART']))->format('Y-m-d H:i:s'); + } else { + $rrule_array['DTSTART'] = (new \DateTime($rrule_array['DTSTART']))->format('Y-m-d'); + } + if ($recurring_dates->rrule) { + $rule_json = json_encode($rrule_array); + } + }else{ + $rule_json = ''; + } + + $this->setAttribute('class', 'uk-input main-input'); + if ($rule_json) { + $this->setAttribute('value', [$rule_json]); + } + $this->setAttribute('x-ref', 'main-input'); + $this->setAttribute('x-model', '_rrule'); + $this->setAttribute('data-rrule', $rule_json); + $this->setAttribute('type', 'hidden'); + $this->setAttribute('data-settings', $recurring_dates->settings); + + $out = ""; + $filePath = "{$this->config->paths->siteModules}FieldtypeRecurringDates/partials/AlpineComponent.php"; + $alpineComponent = wireRenderFile($filePath, [ + 'fieldtype' => $this->hasFieldtype, + 'inputfield' => $this, + 'occurrences' => $occurrences, + 'inputfieldValue' => $recurring_dates + ]); + + $out .= $alpineComponent; + return $out; + } + + + public function ___renderValue() + { + $fieldtype = $this->hasFieldtype; + return $fieldtype->markupValue($this->hasPage, $this->hasField, $this->value); + } + + public function __getEventsUrl() + { } - public function ___processInput(WireInputData $input) - { - $name = $this->attr('name'); - $recurring_date_obj = new RecurringDate(); - $value = $input[$name]; - $settings = $input[$name . "_settings"]; - - if ($value === "") return $recurring_date_obj; - - $recurring_date_obj->settings = $settings; - $settings_obj = json_decode($settings, true); - - $value = json_decode($value, true); - if (!$value['DTSTART']) { - return $recurring_date_obj; - } - if ($settings_obj['limit_mode'] == "count") { - unset($value['UNTIL']); - } - if ($settings_obj['limit_mode'] == "until") { - unset($value['COUNT']); - } - // New RRule from input - $rrule = new RRule($value); - $recurring_date_obj->rrule = $rrule; - - // Compare existing value with new RRule array - $existing_rule = null; - if ($this->attr('value')->rrule) { - $existing_rule = $this->attr('value')->rrule->getRule(); - } - - // Check if RRule array value is different than existing one - if ($existing_rule !== $rrule->getRule()) { - foreach ($rrule as $date) { - $occurrence_date = new Occurrence(); - $occurrence_date->excluded = false; - $occurrence_date->date = $date; - $recurring_date_obj->occurrences->add($occurrence_date); - } - - $this->val($recurring_date_obj); - $this->trackChange('value'); - return $this; - } - return $this; - - } - - public function ___getConfigInputfields() { - // Get the defaults and $inputfields wrapper we can add to - $inputfields = parent::___getConfigInputfields(); + public function ___processInput(WireInputData $input) + { + $name = $this->attr('name'); + $recurring_date_obj = new RecurringDate(); + $value = $input[$name]; + $settings = $input[$name . "_settings"]; + if ($value === "") return $recurring_date_obj; + + $recurring_date_obj->settings = $settings; + $settings_obj = json_decode($settings, true); + + $value = json_decode($value, true); + if (!$value['DTSTART']) { + return $recurring_date_obj; + } + if ($settings_obj['limit_mode'] == "count") { + unset($value['UNTIL']); + } + if ($settings_obj['limit_mode'] == "until") { + unset($value['COUNT']); + } + // New RRule from input + $rrule = new RRule($value); + $recurring_date_obj->rrule = $rrule; + + // Compare existing value with new RRule array + $existing_rule = null; + if ($this->attr('value')->rrule) { + $existing_rule = $this->attr('value')->rrule->getRule(); + } + + // Check if RRule array value is different than existing one + if ($existing_rule !== $rrule->getRule()) { + + $this->val($recurring_date_obj); + $this->trackChange('value'); + return $this; + } + return $this; + + } + + /** + * Get setting + * + * @param string $key + * @return mixed + * + */ + + public function getDateStartInputType() + { + switch ($this->startDateInput) { + case "datetime": + return "datetime-local"; + default: + return "date"; + } + } + + public function ___getConfigInputfields() + { + // Get the defaults and $inputfields wrapper we can add to + $inputfields = parent::___getConfigInputfields(); // Add a new Inputfield to it $f = $this->modules->get('InputfieldInteger'); $f->attr('name', 'pageSize'); - $f->label = 'Page size'; + $f->label = $this->_('Page size'); $f->value = $this->pageSize; $inputfields->add($f); - return $inputfields; - } + /** @var InputfieldSelect $f */ + $f = $this->modules->get('InputfieldSelect'); + $f->attr('name', 'startDateInput'); + $f->label = $this->_("Input type for start date"); + $f->addOptions([ + 'date' => $this->_('Date'), + 'datetime' => $this->_('Both date and time')]); + //bd($this->startDateInput); + $f->val($this->getSetting('startDateInput')); + + $inputfields->add($f); + + return $inputfields; + } + + public function ___getConfigAllowContext(Field $field) + { + $a = array('pageSize', 'startDateInput'); + return array_merge(parent::___getConfigAllowContext($field), $a); + } + } diff --git a/OccurrenceArray.php b/OccurrenceArray.php index ba7a900..e6eb1cb 100644 --- a/OccurrenceArray.php +++ b/OccurrenceArray.php @@ -3,17 +3,12 @@ class OccurrenceArray extends PaginatedArray { - /** - * Is given item valid to store in this EventArray? - * @return Occurrence $item - */ - public function makeBlankItem() { return $this->wire(new Occurrence()); } - public function isValidItem($item) + public function isValidItem($item): bool { return $item instanceof Occurrence; } @@ -40,8 +35,6 @@ public function __toString() ] ]; foreach ($this->data as $item) $a['dates'][] = (string)$item; - //return implode("\n", $a); - bd($this); return json_encode($a, true); } diff --git a/RecurringDatesFinder/RecurringDatesFinder.module b/RecurringDatesFinder/RecurringDatesFinder.module index 8fe112b..1c5c73f 100644 --- a/RecurringDatesFinder/RecurringDatesFinder.module +++ b/RecurringDatesFinder/RecurringDatesFinder.module @@ -10,23 +10,27 @@ class RecurringDatesFinder extends WireData implements Module 'icon' => 'search' ); } + /** - * @param $start - * @param $end - * @param $selector - * @param $options - * @return array|WireArray|void + * @param $start string|int + * @param $end string|int + * @param $selector string + * @param $options array + * @return WireArray * @throws WireException */ public function ___getRecurringFieldQueries($start, $end, $selector, $options) { $selected_pages = null; + $field_queries = new WireArray(); $recurring_fields = $this->fields->find('type=FieldtypeRecurringDates'); - if (!$recurring_fields->count) return; + if (!$recurring_fields->count) return $field_queries; + $default = [ 'fields' => '', ]; + $options = array_merge($default, $options); if ($options['fields']) { $selected_fields = implode('|', $this->sanitizer->array($options['fields'])); @@ -37,9 +41,11 @@ class RecurringDatesFinder extends WireData implements Module } if ($selector) { - $selector .= ",$recurring_fields>=$start, $recurring_fields<=$end"; - $selected_pages = $this->pages->findIDs($selector); + $selector .= ", $recurring_fields>=$start, $recurring_fields<=$end"; + $selected_pages = $this->pages->findRaw($selector, 'title'); } + if (!count($selected_pages)) return $field_queries; + $selected_pages = array_keys($selected_pages); $start = $this->sanitizer->date($start); $end = $this->sanitizer->date($end); @@ -49,11 +55,8 @@ class RecurringDatesFinder extends WireData implements Module if ($end) $end = $this->datetime('Y-m-d H:i:s', $end); - /** @var DatabaseQuerySelect $subquery */ - $field_queries = new WireArray(); - + /** @var Field $field */ foreach ($recurring_fields as $field) { - /** @var Field $field */ $table = $field->getTable(); $query = "SELECT '{$field->name}' as field, data as date, pages_id as id FROM $table "; $where = []; @@ -71,6 +74,7 @@ class RecurringDatesFinder extends WireData implements Module } $field_queries->add($query); } + return $field_queries; } @@ -81,19 +85,21 @@ class RecurringDatesFinder extends WireData implements Module $union_query = $field_queries->implode(" UNION All ", function ($item) { return $item; }); - $union_query .= "ORDER BY date"; + $union_query .= "ORDER BY date ASC"; $pdo = $this->database->prepare($union_query); $pdo->bindValue(':start', $start); $pdo->bindValue(':end', $end); $pdo->execute(); return $pdo->fetchAll(\PDO::FETCH_ASSOC); - } else { - + } elseif($field_queries->count == 1) { $pdo = $this->database->prepare($field_queries->first()); $pdo->bindValue(':start', $start); $pdo->bindValue(':end', $end); $pdo->execute(); return $pdo->fetchAll(\PDO::FETCH_ASSOC); + }else{ + return false; } + } } diff --git a/composer.json b/composer.json index e15e65b..0481fff 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,6 @@ "wireframe-framework/processwire-composer-installer": "^1.1", "php": ">=7.3", "rlanvin/php-rrule": "^2.3", - "elabx/modulejs-alpinejs": "dev-main" + "elabx/processwire-alpinejs": "^0.0.1" } } diff --git a/partials/AlpineComponent.php b/partials/AlpineComponent.php index a4a8b7a..d30f31c 100644 --- a/partials/AlpineComponent.php +++ b/partials/AlpineComponent.php @@ -29,11 +29,10 @@
-