From 1d95a42e5566860f08a5554c71be9752af1f52e2 Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Sat, 13 Jan 2024 15:56:58 -0800 Subject: [PATCH 1/8] Implement naive feed configuration storage --- src/Plugin.php | 3 + src/base/PluginTrait.php | 10 +++ .../FeedConfigStorageController.php | 66 +++++++++++++++++ src/console/controllers/FeedsController.php | 2 + src/models/FeedModel.php | 49 +++++++++++++ src/services/FeedConfigStorage.php | 70 +++++++++++++++++++ src/services/Feeds.php | 26 +------ 7 files changed, 202 insertions(+), 24 deletions(-) create mode 100644 src/console/controllers/FeedConfigStorageController.php create mode 100644 src/services/FeedConfigStorage.php diff --git a/src/Plugin.php b/src/Plugin.php index 7925e88b..166e777a 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -7,6 +7,7 @@ use craft\events\RegisterUrlRulesEvent; use craft\feedme\base\PluginTrait; use craft\feedme\models\Settings; +use craft\feedme\services\FeedConfigStorage; use craft\feedme\services\DataTypes; use craft\feedme\services\Elements; use craft\feedme\services\Feeds; @@ -26,6 +27,7 @@ /** * Class Plugin * + * @property-read FeedConfigStorage $config * @property-read DataTypes $data * @property-read Elements $elements * @property-read Feeds $feeds @@ -50,6 +52,7 @@ public static function config(): array { return [ 'components' => [ + 'config' => ['class' => FeedConfigStorage::class], 'data' => ['class' => DataTypes::class], 'elements' => ['class' => Elements::class], 'feeds' => ['class' => Feeds::class], diff --git a/src/base/PluginTrait.php b/src/base/PluginTrait.php index cdd62783..5ac1d3ed 100644 --- a/src/base/PluginTrait.php +++ b/src/base/PluginTrait.php @@ -4,6 +4,7 @@ use Craft; use craft\feedme\Plugin; +use craft\feedme\services\FeedConfigStorage; use craft\feedme\services\DataTypes; use craft\feedme\services\Elements; use craft\feedme\services\Feeds; @@ -78,6 +79,15 @@ public static function debug($message): void // Public Methods // ========================================================================= + /** + * @return FeedConfigStorage + * @throws \yii\base\InvalidConfigException + */ + public function getFeedConfigStorage(): FeedConfigStorage + { + return $this->get('feedConfigStorage'); + } + /** * @return DataTypes * @throws \yii\base\InvalidConfigException diff --git a/src/console/controllers/FeedConfigStorageController.php b/src/console/controllers/FeedConfigStorageController.php new file mode 100644 index 00000000..317e89b4 --- /dev/null +++ b/src/console/controllers/FeedConfigStorageController.php @@ -0,0 +1,66 @@ +config->write() ? ExitCode::CANTCREAT : ExitCode::OK; + } + + /** + * Reads feeds records from file + * + * @return int + */ + public function actionRead(): int + { + $result = Plugin::$plugin->config->read(); + + if($result->success) { + return ExitCode::OK; + } + + $this->stderr("FAILED FEEDS" . PHP_EOL, Console::FG_RED); + foreach($result->failed_feeds as $feed) { + $this->stderr("({$feed->id}) {$feed->name}".PHP_EOL, Console::FG_RED); + } + + if(count($result->success_feeds) > 0) { + $this->stdout(PHP_EOL . "SUCCESSFUL FEEDS" . PHP_EOL, Console::FG_GREEN); + foreach ($result->success_feeds as $feed) { + $this->stdout("({$feed->id}) {$feed->name} " . PHP_EOL, Console::FG_GREEN); + } + } + + return ExitCode::UNSPECIFIED_ERROR; + } +} diff --git a/src/console/controllers/FeedsController.php b/src/console/controllers/FeedsController.php index be29ded4..280de6ec 100644 --- a/src/console/controllers/FeedsController.php +++ b/src/console/controllers/FeedsController.php @@ -9,6 +9,8 @@ use yii\console\ExitCode; /** + * Queues up feed imports + * * @property Plugin $module */ class FeedsController extends Controller diff --git a/src/models/FeedModel.php b/src/models/FeedModel.php index 831dfd24..7c12afd2 100644 --- a/src/models/FeedModel.php +++ b/src/models/FeedModel.php @@ -10,6 +10,8 @@ use craft\feedme\base\ElementInterface; use craft\feedme\helpers\DuplicateHelper; use craft\feedme\Plugin; +use craft\helpers\Db; +use craft\helpers\Json; use DateTime; /** @@ -254,4 +256,51 @@ public function rules(): array [['backup', 'setEmptyValues'], 'boolean'], ]; } + + /** + * Retrieves the attributes in a format for a record + * + * @return array An array containing the record attributes + */ + public function getRecordAttributes(): array + { + $attributes = [ + "name" => $this->name, + "feedUrl" => $this->feedUrl, + "feedType" => $this->feedType, + "primaryElement" => $this->primaryElement, + "elementType" => $this->elementType, + "siteId" => $this->siteId, + "singleton" => $this->singleton, + "duplicateHandle" => $this->duplicateHandle, + "updateSearchIndexes" => $this->updateSearchIndexes, + "paginationNode" => $this->paginationNode, + "passkey" => $this->passkey, + "backup" => $this->backup, + "setEmptyValues" => $this->setEmptyValues, + + // These might be automatically updated, but in the case of writing + // the feed record to a file, we want these values. + "dateCreated" => Db::prepareDateForDb($this->dateCreated), + "dateUpdated" => Db::prepareDateForDb($this->dateUpdated) + ]; + + if ($this->elementGroup) { + $attributes["elementGroup"] = Json::encode($this->elementGroup); + } + + if ($this->duplicateHandle) { + $attributes["duplicateHandle"] = Json::encode($this->duplicateHandle); + } + + if ($this->fieldMapping) { + $attributes["fieldMapping"] = Json::encode($this->fieldMapping); + } + + if ($this->fieldUnique) { + $attributes["fieldUnique"] = Json::encode($this->fieldUnique); + } + + return $attributes; + } } diff --git a/src/services/FeedConfigStorage.php b/src/services/FeedConfigStorage.php new file mode 100644 index 00000000..743b65ea --- /dev/null +++ b/src/services/FeedConfigStorage.php @@ -0,0 +1,70 @@ + $feed->id] + $feed->getRecordAttributes(); }, + Plugin::getInstance()->getFeeds()->getFeeds() + ); + + $fileName = $this->defaultFileName; + $fileContents = Yaml::dump($feeds, JSON_PRETTY_PRINT); + + return file_put_contents($fileName, $fileContents) !== false; + } + + /** + * Reads feed data from a YAML file and processes each feed. + * + * @return \stdClass The result object containing success flag, successful feeds, and failed feeds. + * @throws \yii\base\InvalidConfigException If the configuration is invalid. + */ + public function read(): \stdClass { + $result = (object)["success" => true, "success_feeds" => [], "failed_feeds" => []]; + $fileName = $this->defaultFileName; + $feeds = Yaml::parse(file_get_contents($fileName)); + foreach ($feeds as $feed) { + $model = Plugin::getInstance()->getFeeds()->getFeedById($feed['id']); + if ($model) { + $model->setAttributes($feed); + $success = Plugin::getInstance()->getFeeds()->saveFeed($model); + if ($success) { + $result->success_feeds[] = $model; + } else { + $result->failed_feeds[] = $model; + } + } + } + + if(count($result->failed_feeds) > 0) { + $result->success = false; + } + + return $result; + } +} diff --git a/src/services/Feeds.php b/src/services/Feeds.php index f0defbf3..17670c90 100644 --- a/src/services/Feeds.php +++ b/src/services/Feeds.php @@ -119,30 +119,8 @@ public function saveFeed(FeedModel $model, bool $runValidation = true): bool } } - $record->name = $model->name; - $record->feedUrl = $model->feedUrl; - $record->feedType = $model->feedType; - $record->primaryElement = $model->primaryElement; - $record->elementType = $model->elementType; - $record->siteId = $model->siteId; - $record->singleton = $model->singleton; - $record->duplicateHandle = $model->duplicateHandle; - $record->updateSearchIndexes = $model->updateSearchIndexes; - $record->paginationNode = $model->paginationNode; - $record->passkey = $model->passkey; - $record->backup = $model->backup; - $record->setEmptyValues = $model->setEmptyValues; - - if ($model->elementGroup) { - $record->setAttribute('elementGroup', Json::encode($model->elementGroup)); - } - - if ($model->fieldMapping) { - $record->setAttribute('fieldMapping', Json::encode($model->fieldMapping)); - } - - if ($model->fieldUnique) { - $record->setAttribute('fieldUnique', Json::encode($model->fieldUnique)); + foreach($model->getRecordAttributes() as $name => $value) { + $record->setAttribute($name, $value); } if ($isNewModel) { From e72cc9af6f7ce6381c8bacd049fc1e21170f6d93 Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Fri, 2 Feb 2024 09:07:18 -0800 Subject: [PATCH 2/8] [C] Mkdir before writing --- src/services/FeedConfigStorage.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/services/FeedConfigStorage.php b/src/services/FeedConfigStorage.php index 743b65ea..8ea1b236 100644 --- a/src/services/FeedConfigStorage.php +++ b/src/services/FeedConfigStorage.php @@ -35,6 +35,8 @@ function($feed) { return ["id" => $feed->id] + $feed->getRecordAttributes(); }, $fileName = $this->defaultFileName; $fileContents = Yaml::dump($feeds, JSON_PRETTY_PRINT); + mkdir(dirname($this->defaultFileName), 0777, true); + return file_put_contents($fileName, $fileContents) !== false; } From d0a09405f4efbf404ffb9325aa49a1cd75271045 Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Fri, 2 Feb 2024 09:43:03 -0800 Subject: [PATCH 3/8] [B] Fix reading of unsafe attrs --- src/services/FeedConfigStorage.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/services/FeedConfigStorage.php b/src/services/FeedConfigStorage.php index 8ea1b236..b473f0bc 100644 --- a/src/services/FeedConfigStorage.php +++ b/src/services/FeedConfigStorage.php @@ -3,6 +3,7 @@ namespace craft\feedme\services; use craft\base\Component; +use craft\feedme\models\FeedModel; use craft\feedme\Plugin; use Symfony\Component\Yaml\Yaml; @@ -52,14 +53,15 @@ public function read(): \stdClass { $feeds = Yaml::parse(file_get_contents($fileName)); foreach ($feeds as $feed) { $model = Plugin::getInstance()->getFeeds()->getFeedById($feed['id']); - if ($model) { - $model->setAttributes($feed); - $success = Plugin::getInstance()->getFeeds()->saveFeed($model); - if ($success) { - $result->success_feeds[] = $model; - } else { - $result->failed_feeds[] = $model; - } + if (!$model) { + $model = new FeedModel(); + } + $model->setAttributes($feed, false); + $success = Plugin::getInstance()->getFeeds()->saveFeed($model); + if ($success) { + $result->success_feeds[] = $model; + } else { + $result->failed_feeds[] = $model; } } From 562d0fe945490f295787d06e56de2cff866a6ff9 Mon Sep 17 00:00:00 2001 From: Kyle Pratuch Date: Fri, 2 Feb 2024 14:17:10 -0800 Subject: [PATCH 4/8] [C] Add check for feeds.yaml --- src/services/FeedConfigStorage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/FeedConfigStorage.php b/src/services/FeedConfigStorage.php index b473f0bc..7663b26e 100644 --- a/src/services/FeedConfigStorage.php +++ b/src/services/FeedConfigStorage.php @@ -36,7 +36,7 @@ function($feed) { return ["id" => $feed->id] + $feed->getRecordAttributes(); }, $fileName = $this->defaultFileName; $fileContents = Yaml::dump($feeds, JSON_PRETTY_PRINT); - mkdir(dirname($this->defaultFileName), 0777, true); + if(!file_exists($this->defaultFileName)) mkdir(dirname($this->defaultFileName), 0777, true); return file_put_contents($fileName, $fileContents) !== false; } From 3d6bcd69d5d8bc7891320a4115ededa0887ee25f Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Fri, 2 Feb 2024 15:10:02 -0800 Subject: [PATCH 5/8] [C] Delete feeds before reading new ones --- src/services/FeedConfigStorage.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/services/FeedConfigStorage.php b/src/services/FeedConfigStorage.php index 7663b26e..14022be0 100644 --- a/src/services/FeedConfigStorage.php +++ b/src/services/FeedConfigStorage.php @@ -3,8 +3,8 @@ namespace craft\feedme\services; use craft\base\Component; -use craft\feedme\models\FeedModel; use craft\feedme\Plugin; +use craft\feedme\records\FeedRecord; use Symfony\Component\Yaml\Yaml; /** @@ -52,16 +52,16 @@ public function read(): \stdClass { $fileName = $this->defaultFileName; $feeds = Yaml::parse(file_get_contents($fileName)); foreach ($feeds as $feed) { - $model = Plugin::getInstance()->getFeeds()->getFeedById($feed['id']); - if (!$model) { - $model = new FeedModel(); - } - $model->setAttributes($feed, false); - $success = Plugin::getInstance()->getFeeds()->saveFeed($model); + Plugin::getInstance()->getFeeds()->deleteFeedById($feed['id']); + + $record = new FeedRecord(); + $record->setAttributes($feed, false); + $record->save(false); + $success = (bool) $record->id; if ($success) { - $result->success_feeds[] = $model; + $result->success_feeds[] = $record; } else { - $result->failed_feeds[] = $model; + $result->failed_feeds[] = $record; } } From 80f66678dd1b57bd2ce7f07e1cfc9bfb094fa0be Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Wed, 14 Feb 2024 11:34:22 -0800 Subject: [PATCH 6/8] [C] Use uids for element selection rather than ids --- src/elements/Entry.php | 36 ++++++++++++++++--- src/fields/Entries.php | 2 +- .../_includes/elements/entries/column.html | 10 +++--- .../_includes/elements/entries/groups.html | 26 +++++++------- .../_includes/elements/entries/map.html | 8 ++--- 5 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/elements/Entry.php b/src/elements/Entry.php index c03b2992..f1990c0c 100644 --- a/src/elements/Entry.php +++ b/src/elements/Entry.php @@ -102,10 +102,15 @@ public function getQuery($settings, array $params = []): mixed $section = $this->element->getSection(); } + list($sectionId, $entryTypeId) = $this->getSectionAndElementGroupIdsFromUids( + $settings['elementGroup'][EntryElement::class]['section'], + $settings['elementGroup'][EntryElement::class]['entryType'] + ); + $query = EntryElement::find() ->status(null) - ->sectionId($settings['elementGroup'][EntryElement::class]['section']) - ->typeId($settings['elementGroup'][EntryElement::class]['entryType']); + ->sectionId($sectionId) + ->typeId($entryTypeId); if (isset($section) && $section->propagationMethod === Section::PROPAGATION_METHOD_CUSTOM) { $query->site('*') @@ -119,16 +124,37 @@ public function getQuery($settings, array $params = []): mixed return $query; } + + public function getSectionAndElementGroupIdsFromUids(string $sectionUid, string $elementGroupUid): array + { + $section = Craft::$app->sections->getSectionByUid($sectionUid); + $entryTypes = $section->getEntryTypes(); + $entryTypeId = null; + foreach ($entryTypes as $entryType) { + if ($entryType->uid === $elementGroupUid) { + $entryTypeId = $entryType->id; + break; + } + } + return [$section->id, $entryTypeId]; + } + /** * @inheritDoc */ public function setModel($settings): ElementInterface { $this->element = new EntryElement(); - $this->element->sectionId = $settings['elementGroup'][EntryElement::class]['section']; - $this->element->typeId = $settings['elementGroup'][EntryElement::class]['entryType']; - $section = Craft::$app->getSections()->getSectionById($this->element->sectionId); + list($sectionId, $entryTypeId) = $this->getSectionAndElementGroupIdsFromUids( + $settings['elementGroup'][EntryElement::class]['section'], + $settings['elementGroup'][EntryElement::class]['entryType'] + ); + + $this->element->sectionId = $sectionId; + $this->element->typeId = $entryTypeId; + + $section = Craft::$app->getSections()->getSectionByUid($this->element->section->uid); $siteId = Hash::get($settings, 'siteId'); if ($siteId) { diff --git a/src/fields/Entries.php b/src/fields/Entries.php index 6cf59dbc..e781d54a 100644 --- a/src/fields/Entries.php +++ b/src/fields/Entries.php @@ -224,7 +224,7 @@ private function _createElement($dataValue): ?int $element->typeId = $typeId; $siteId = Hash::get($this->feed, 'siteId'); - $section = Craft::$app->getSections()->getSectionById($element->sectionId); + $section = Craft::$app->getSections()->getSectionByUid($element->sectionUid); if ($siteId) { $element->siteId = $siteId; diff --git a/src/templates/_includes/elements/entries/column.html b/src/templates/_includes/elements/entries/column.html index b3306e9c..67668511 100644 --- a/src/templates/_includes/elements/entries/column.html +++ b/src/templates/_includes/elements/entries/column.html @@ -1,9 +1,9 @@ -{% set sectionId = feed.elementGroup[elementType].section %} -{% set entryTypeId = feed.elementGroup[elementType].entryType %} +{% set sectionUid = feed.elementGroup[elementType].section %} +{% set entryTypeUid = feed.elementGroup[elementType].entryType %} -{% if sectionId and entryTypeId %} - {% set section = craft.app.sections.getSectionById(sectionId) %} - {% set entryType = craft.app.sections.getEntryTypeById(entryTypeId) %} +{% if sectionUid and entryTypeUid %} + {% set section = craft.app.sections.getSectionByUid(sectionUid) %} + {% set entryType = craft.app.sections.getEntryTypeByUid(entryTypeUid) %} {% if section and entryType %} {{ section.name }} diff --git a/src/templates/_includes/elements/entries/groups.html b/src/templates/_includes/elements/entries/groups.html index ae20ad41..3d05e6b8 100644 --- a/src/templates/_includes/elements/entries/groups.html +++ b/src/templates/_includes/elements/entries/groups.html @@ -7,24 +7,22 @@ {# Create a section-indexed array of element types #} {% set entryTypes = [] %} {% for section in sections %} - {% set options = craft.feedme.getSelectOptions(section.model.getEntryTypes()) %} - + {% set options = craft.feedme.getSelectOptions(section.model.getEntryTypes(), 'name', 'uid') %} {# We have to prefix the index, otherwise Twig doesn't maintain numbered index correctly #} - {% set entryTypes = entryTypes|merge({ ('item_' ~ section.id): options }) %} + {% set entryTypes = entryTypes|merge({ ('item_' ~ section.model.uid): options }) %} {% endfor %} -{% set sectionId = null %} -{% set entryTypeId = null %} +{% set sectionUid = null %} +{% set entryTypeUid = null %} {# Load saved values for feed #} {% if feed.elementGroup[elementType] is defined %} - {% set sectionId = feed.elementGroup[elementType].section ?? null %} - {% set entryTypeId = feed.elementGroup[elementType].entryType ?? null %} + {% set sectionUid = feed.elementGroup[elementType].section ?? null %} + {% set entryTypeUid = feed.elementGroup[elementType].entryType ?? null %} {% endif %} -{% if sectionId %} - {% set section = craft.app.sections.getSectionById(sectionId) %} - +{% if sectionUid %} + {% set section = craft.app.sections.getSectionByUid(sectionUid) %} {% if section %} {% set sectionEntryTypes = section.getEntryTypes() %} {% endif %} @@ -39,8 +37,8 @@ class: 'element-parent-group', id: 'elementGroup-' ~ elementType ~ '-section', name: 'elementGroup[' ~ elementType ~ '][section]', - options: craft.feedme.getSelectOptions(sections|map(s => s.model)), - value: sectionId ?? '', + options: craft.feedme.getSelectOptions(sections|map(s => s.model), 'name', 'uid'), + value: sectionUid ?? '', errors: feed.getErrors('elementGroup'), required: true, }) }} @@ -51,8 +49,8 @@ class: 'element-child-group', id: 'elementGroup-' ~ elementType ~ '-entryType', name: 'elementGroup[' ~ elementType ~ '][entryType]', - options: craft.feedme.getSelectOptions(sectionEntryTypes), - value: entryTypeId ?? '', + options: craft.feedme.getSelectOptions(sectionEntryTypes, 'name', 'uid'), + value: entryTypeUid ?? '', errors: feed.getErrors('elementGroup'), required: true, }) }} diff --git a/src/templates/_includes/elements/entries/map.html b/src/templates/_includes/elements/entries/map.html index cb7cd06a..7d157b29 100644 --- a/src/templates/_includes/elements/entries/map.html +++ b/src/templates/_includes/elements/entries/map.html @@ -2,11 +2,11 @@ {% import 'feed-me/_macros' as feedMeMacro %} {% if feed.elementGroup %} - {% set sectionId = feed.elementGroup[feed.elementType].section %} - {% set entryTypeId = feed.elementGroup[feed.elementType].entryType %} + {% set sectionUid = feed.elementGroup[feed.elementType].section %} + {% set entryTypeUid = feed.elementGroup[feed.elementType].entryType %} - {% set section = craft.app.sections.getSectionById(sectionId) %} - {% set entryType = craft.app.sections.getEntryTypeById(entryTypeId) %} + {% set section = craft.app.sections.getSectionByUid(sectionUid) %} + {% set entryType = craft.app.sections.getEntryTypeByUid(entryTypeUid) %} {% endif %} From e8292d43af0229a3e024f0192bb6a94560a696ad Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Fri, 22 Mar 2024 14:23:13 -0700 Subject: [PATCH 7/8] [C] Delete all feeds before reading from YAML --- src/services/FeedConfigStorage.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/services/FeedConfigStorage.php b/src/services/FeedConfigStorage.php index 14022be0..c99f5aa9 100644 --- a/src/services/FeedConfigStorage.php +++ b/src/services/FeedConfigStorage.php @@ -42,18 +42,22 @@ function($feed) { return ["id" => $feed->id] + $feed->getRecordAttributes(); }, } /** - * Reads feed data from a YAML file and processes each feed. + * Reads feed data from a YAML file and imports each feed. * * @return \stdClass The result object containing success flag, successful feeds, and failed feeds. * @throws \yii\base\InvalidConfigException If the configuration is invalid. */ public function read(): \stdClass { $result = (object)["success" => true, "success_feeds" => [], "failed_feeds" => []]; + + // Delete all feeds + foreach(Plugin::getInstance()->getFeeds()->getFeeds() as $feed) { + Plugin::getInstance()->getFeeds()->deleteFeedById($feed['id']); + } + $fileName = $this->defaultFileName; $feeds = Yaml::parse(file_get_contents($fileName)); foreach ($feeds as $feed) { - Plugin::getInstance()->getFeeds()->deleteFeedById($feed['id']); - $record = new FeedRecord(); $record->setAttributes($feed, false); $record->save(false); From 2288f826e16db875f1d733a3bd6e27eb69814117 Mon Sep 17 00:00:00 2001 From: Lucas Thurston Date: Thu, 11 Apr 2024 16:31:45 -0700 Subject: [PATCH 8/8] [F] Parse feedUrl with Twig This lets us do things like put the current date into the feedUrl. --- src/services/DataTypes.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/services/DataTypes.php b/src/services/DataTypes.php index 0ec71b8f..79d8bbdf 100644 --- a/src/services/DataTypes.php +++ b/src/services/DataTypes.php @@ -234,10 +234,15 @@ public function getRawData($url, $feedId = null): array */ public function getFeedData($feedModel, bool $usePrimaryElement = true): mixed { - $feedDataResponse = $feedModel->getDataType()->getFeed($feedModel->feedUrl, $feedModel, $usePrimaryElement); + // Dynamism in the feedUrl -- use twig to inject dates, for example + $twig = \Craft::$app->getView()->getTwig(); + $template = twig_template_from_string($twig, $feedModel->feedUrl); + $feedUrl = $template->render([]); + + $feedDataResponse = $feedModel->getDataType()->getFeed($feedUrl, $feedModel, $usePrimaryElement); $event = new FeedDataEvent([ - 'url' => $feedModel->feedUrl, + 'url' => $feedUrl, 'response' => $feedDataResponse, 'feedId' => $feedModel->id, ]);